aboutsummaryrefslogtreecommitdiff
path: root/www
diff options
context:
space:
mode:
authorAndrew Pantyukhin <sat@FreeBSD.org>2006-08-06 21:57:57 +0000
committerAndrew Pantyukhin <sat@FreeBSD.org>2006-08-06 21:57:57 +0000
commitb12accf71957a01d1be8255d4080d7f9a97f4d97 (patch)
tree6a3bd90cc818ca6f3f6fb6089c4db8075032765b /www
parent178abbd25e4bb310814f32b28ba7fddd36b9ec1b (diff)
downloadports-b12accf71957a01d1be8255d4080d7f9a97f4d97.tar.gz
ports-b12accf71957a01d1be8255d4080d7f9a97f4d97.zip
- Update to 2.6.STABLE2.
- Include most of the post-STABLE2 changes/bugfixes published at <http://www.squid-cache.org/Versions/v2/2.6/changesets/>. - Remove the local fix for the problem that ipfw(4) support was not working because the problem was fixed upstream. - Remove the SQUID_IPFW option again, ipfw(4) should now work out of the box as in earlier Squid versions. - Add ICAP support. PR: ports/101422 Submitted by: Thomas-Martin Seck <tmseck@netcologne.de> (maintainer)
Notes
Notes: svn path=/head/; revision=169859
Diffstat (limited to 'www')
-rw-r--r--www/squid26/Makefile22
-rw-r--r--www/squid26/distinfo39
-rw-r--r--www/squid26/files/icap-2.6-bootstrap.patch473
-rw-r--r--www/squid26/files/icap-2.6-core.patch7159
-rw-r--r--www/squid26/files/patch-changeset.10801284
-rw-r--r--www/squid26/files/patch-src-client_side.c16
-rw-r--r--www/squid27/Makefile22
-rw-r--r--www/squid27/distinfo39
-rw-r--r--www/squid27/files/icap-2.6-bootstrap.patch473
-rw-r--r--www/squid27/files/icap-2.6-core.patch7159
-rw-r--r--www/squid27/files/patch-changeset.10801284
-rw-r--r--www/squid27/files/patch-src-client_side.c16
12 files changed, 15348 insertions, 638 deletions
diff --git a/www/squid26/Makefile b/www/squid26/Makefile
index 54f8810d1153..284fc896064b 100644
--- a/www/squid26/Makefile
+++ b/www/squid26/Makefile
@@ -75,8 +75,7 @@
# Enable experimental multicast notification of cachemisses.
PORTNAME= squid
-PORTVERSION= 2.6.1
-PORTREVISION= 1
+PORTVERSION= 2.6.2
CATEGORIES= www
MASTER_SITES= ftp://ftp.squid-cache.org/pub/%SUBDIR%/ \
ftp://archive.progeny.com/squid/%SUBDIR%/ \
@@ -88,7 +87,7 @@ MASTER_SITES= ftp://ftp.squid-cache.org/pub/%SUBDIR%/ \
ftp://ftp.ccs.neu.edu/pub/mirrors/squid.nlanr.net/pub/%SUBDIR%/ \
${MASTER_SITE_RINGSERVER:S,%SUBDIR%,net/www/squid/&,}
MASTER_SITE_SUBDIR= squid-2/STABLE
-DISTNAME= squid-2.6.STABLE1
+DISTNAME= squid-2.6.STABLE2
DIST_SUBDIR= squid2.6
PATCH_SITES= http://www.squid-cache.org/%SUBDIR%/ \
@@ -101,7 +100,8 @@ PATCH_SITES= http://www.squid-cache.org/%SUBDIR%/ \
http://www1.jp.squid-cache.org/%SUBDIR%/ \
http://www1.tw.squid-cache.org/%SUBDIR%/
PATCH_SITE_SUBDIR= Versions/v2/2.6/changesets/
-PATCHFILES= 10799.patch
+PATCHFILES= 10894.patch 10895.patch 10896.patch 10898.patch 10899.patch \
+ 10900.patch 10901.patch 10902.patch 10903.patch 10904.patch
PATCH_DIST_STRIP= -p1
MAINTAINER= tmseck@netcologne.de
@@ -144,7 +144,6 @@ OPTIONS= SQUID_LDAP_AUTH "Install LDAP authentication helpers" off \
SQUID_ARP_ACL "Enable ACLs based on ethernet address" off \
SQUID_PF "Enable transparent proxying with PF" off \
SQUID_IPFILTER "Enable transp. proxying with IPFilter" off \
- SQUID_IPFW "Enable transparent proxying with IPFW" off \
SQUID_FOLLOW_XFF "Follow X-Forwarded-For headers" off \
SQUID_ICAP "Enable ICAP client functionality" off \
SQUID_AUFS "Enable the aufs storage scheme" off \
@@ -187,7 +186,7 @@ libexec= cachemgr.cgi digest_pw_auth diskd-daemon ip_user_check \
libexec+= unlinkd
.endif
-sbin= RunCache squidclient squid
+sbin= RunCache cossdump squidclient squid
CONFIGURE_ARGS= --bindir=${PREFIX}/sbin \
--sbindir=${PREFIX}/sbin \
@@ -331,17 +330,14 @@ IGNORE= IPFilter headers are not part of the base system
CONFIGURE_ARGS+= --enable-ipf-transparent
.endif
.endif
-.if defined(WITH_SQUID_IPFW)
-CFLAGS+= -DIPFW_TRANSPARENT
-.endif
.if defined(WITH_SQUID_FOLLOW_XFF)
CONFIGURE_ARGS+= --enable-follow-x-forwarded-for
.endif
.if defined(WITH_SQUID_ICAP)
-IGNORE= patches for ICAP support are not yet updated
-EXTRA_PATCHES+=
-#CONFIGURE_ARGS+= --enable-icap-support
-#error_files+= ERR_ICAP_FAILURE
+EXTRA_PATCHES+= ${PATCHDIR}/icap-2.6-bootstrap.patch \
+ ${PATCHDIR}/icap-2.6-core.patch
+CONFIGURE_ARGS+= --enable-icap-support
+error_files+= ERR_ICAP_FAILURE
.endif
.if !defined(WITHOUT_SQUID_KQUEUE)
CONFIGURE_ARGS+= --enable-kqueue
diff --git a/www/squid26/distinfo b/www/squid26/distinfo
index 1d11150734c3..f4b602d9732d 100644
--- a/www/squid26/distinfo
+++ b/www/squid26/distinfo
@@ -1,6 +1,33 @@
-MD5 (squid2.6/squid-2.6.STABLE1.tar.bz2) = d6bb23a67b0475cca11d4af8d574d054
-SHA256 (squid2.6/squid-2.6.STABLE1.tar.bz2) = a9efea26f1c3966dff69f80c271a73562afed5c65929d69dab713308dd402ba9
-SIZE (squid2.6/squid-2.6.STABLE1.tar.bz2) = 1212556
-MD5 (squid2.6/10799.patch) = 3a3d941b0d256a1da9ad8f2430da4e2b
-SHA256 (squid2.6/10799.patch) = 0f010962faae226a21761996df7c487ed6ca2d51458e6941a9f2a5b69aa3e6c3
-SIZE (squid2.6/10799.patch) = 1288
+MD5 (squid2.6/squid-2.6.STABLE2.tar.bz2) = 838492f95de0964e31e633bfa07a0682
+SHA256 (squid2.6/squid-2.6.STABLE2.tar.bz2) = 8ceb890161648f26b3c16f07e2e1beecad2b0de0f3f1793142a32b5aa25ef8e6
+SIZE (squid2.6/squid-2.6.STABLE2.tar.bz2) = 1222355
+MD5 (squid2.6/10894.patch) = 8b66b5f16a1563e15690f0b8ecddd5b9
+SHA256 (squid2.6/10894.patch) = cab38b13352135433fb85e04a76182ca96b03e4c6df487b6de25e73b1bf71ffd
+SIZE (squid2.6/10894.patch) = 1303
+MD5 (squid2.6/10895.patch) = 234efdec5f31662d07188829bcd28721
+SHA256 (squid2.6/10895.patch) = 8d12a761c64ca9b8c7f18e4393f47d22e4bd772a788bcbea61c81f48647a8835
+SIZE (squid2.6/10895.patch) = 5885
+MD5 (squid2.6/10896.patch) = 187944a1b8b3e796f5ae5d18b2d66284
+SHA256 (squid2.6/10896.patch) = 0a8d6dd65a3d9d76b9aeb85135f560abe9a53ce17891e866d0e38f14aa4f436b
+SIZE (squid2.6/10896.patch) = 1100
+MD5 (squid2.6/10898.patch) = 830d6788b613b93221d7661bf19946a1
+SHA256 (squid2.6/10898.patch) = f6b95725ba7d78fdbd41a8589229acf9b2128deb109adbe13d5f7e0d81d192f7
+SIZE (squid2.6/10898.patch) = 3611
+MD5 (squid2.6/10899.patch) = dee2d52860f2ee66bb4ecbfbdbf1f66f
+SHA256 (squid2.6/10899.patch) = c3c8b334fe5d6f3e5037e6db4cf6e5049076e07e44df2f5cd8f0f4a9d0fde5fd
+SIZE (squid2.6/10899.patch) = 1641
+MD5 (squid2.6/10900.patch) = 5bb888d3a4041572bc38f9cf6e177e5e
+SHA256 (squid2.6/10900.patch) = 48bc152e1986efb4ef58b64409d062b1a01a09cba0c4dcb31b719bb595c11751
+SIZE (squid2.6/10900.patch) = 917
+MD5 (squid2.6/10901.patch) = 16d5d2bf91a868da672daa8c24f0ca74
+SHA256 (squid2.6/10901.patch) = f0fe03966617b895e1fae361e8aa8557a51433c1c4eec92599424f0d2ece545e
+SIZE (squid2.6/10901.patch) = 1709
+MD5 (squid2.6/10902.patch) = f9b7dd81b26a17e52175d06161b00ee6
+SHA256 (squid2.6/10902.patch) = d63c4dca13096ce3185ad6b15de2f897f24018581a69e611e9a00dbf5842ab59
+SIZE (squid2.6/10902.patch) = 1439
+MD5 (squid2.6/10903.patch) = 008c0c4e8b08def33f48f2706d13433e
+SHA256 (squid2.6/10903.patch) = 727dbe9951d915f7b846ed905148ce4177703dbbfa493d45b5efbb1da61851e0
+SIZE (squid2.6/10903.patch) = 968
+MD5 (squid2.6/10904.patch) = 20d803cd8ede1132d8f8009cc93ca816
+SHA256 (squid2.6/10904.patch) = 36bf8c00084988a850bcbe816cf52a7002e8516806fb7a17438eaeeb389457fa
+SIZE (squid2.6/10904.patch) = 37791
diff --git a/www/squid26/files/icap-2.6-bootstrap.patch b/www/squid26/files/icap-2.6-bootstrap.patch
new file mode 100644
index 000000000000..548a7e97ac89
--- /dev/null
+++ b/www/squid26/files/icap-2.6-bootstrap.patch
@@ -0,0 +1,473 @@
+Patch 2 of 2 to integrate the icap-2_6 branch into the FreeBSD squid port.
+
+Created by Thomas-Martin Seck <tmseck@netcologne.de>.
+
+This patch simulates the autotools bootstrap necessary after applying the
+ICAP patchset.
+
+Please see icap-2.6-core.patch for further information.
+
+Patch last updated: 2006-08-05
+
+--- configure.orig Sat Aug 5 16:24:35 2006
++++ configure Sat Aug 5 16:19:46 2006
+@@ -270,8 +270,8 @@
+ # Identity of this package.
+ PACKAGE_NAME='Squid Web Proxy'
+ PACKAGE_TARNAME='squid'
+-PACKAGE_VERSION='2.6.STABLE2'
+-PACKAGE_STRING='Squid Web Proxy 2.6.STABLE2'
++PACKAGE_VERSION='2.6.STABLE2-CVS'
++PACKAGE_STRING='Squid Web Proxy 2.6.STABLE2-CVS'
+ PACKAGE_BUGREPORT='http://www.squid-cache.org/bugs/'
+
+ ac_default_prefix=/usr/local/squid
+@@ -312,7 +312,7 @@
+ # include <unistd.h>
+ #endif"
+
+-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE build build_cpu build_vendor build_os host host_cpu host_vendor host_os PKGCONFIG CGIEXT ENABLE_WIN32SPECIFIC_TRUE ENABLE_WIN32SPECIFIC_FALSE CACHE_HTTP_PORT CACHE_ICP_PORT LIBDLMALLOC LIB_MALLOC STORE_OBJS STORE_LIBS STORE_MODULES NEED_DISKD_TRUE NEED_DISKD_FALSE REPL_POLICIES REPL_OBJS REPL_LIBS ENABLE_PINGER_TRUE ENABLE_PINGER_FALSE USE_DELAY_POOLS_TRUE USE_DELAY_POOLS_FALSE USE_SNMP_TRUE USE_SNMP_FALSE SNMPLIB makesnmplib ENABLE_HTCP_TRUE ENABLE_HTCP_FALSE ENABLE_SSL_TRUE ENABLE_SSL_FALSE NEED_OWN_MD5_TRUE NEED_OWN_MD5_FALSE SSLLIB ERR_DEFAULT_LANGUAGE ERR_LANGUAGES MAKE_LEAKFINDER_TRUE MAKE_LEAKFINDER_FALSE USE_DNSSERVER_TRUE USE_DNSSERVER_FALSE OPT_DEFAULT_HOSTS AUTH_MODULES AUTH_OBJS AUTH_LIBS BASIC_AUTH_HELPERS NTLM_AUTH_HELPERS DIGEST_AUTH_HELPERS NEGOTIATE_AUTH_HELPERS EXTERNAL_ACL_HELPERS CPP EGREP LIBSASL ENABLE_UNLINKD_TRUE ENABLE_UNLINKD_FALSE RANLIB ac_ct_RANLIB LN_S SH FALSE TRUE RM MV MKDIR LN PERL AR AR_R ALLOCA CRYPTLIB LIB_EPOLL LIB_LDAP LIB_LBER LIB_DB EPOLL_LIBS USE_POLL_TRUE USE_POLL_FALSE USE_EPOLL_TRUE USE_EPOLL_FALSE USE_SELECT_TRUE USE_SELECT_FALSE USE_SELECT_WIN32_TRUE USE_SELECT_WIN32_FALSE USE_KQUEUE_TRUE USE_KQUEUE_FALSE NEED_OWN_SNPRINTF_TRUE NEED_OWN_SNPRINTF_FALSE NEED_OWN_STRSEP_TRUE NEED_OWN_STRSEP_FALSE REGEXLIB LIBREGEX LIBOBJS XTRA_OBJS XTRA_LIBS LTLIBOBJS'
++ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE build build_cpu build_vendor build_os host host_cpu host_vendor host_os PKGCONFIG CGIEXT ENABLE_WIN32SPECIFIC_TRUE ENABLE_WIN32SPECIFIC_FALSE CACHE_HTTP_PORT CACHE_ICP_PORT LIBDLMALLOC LIB_MALLOC STORE_OBJS STORE_LIBS STORE_MODULES NEED_DISKD_TRUE NEED_DISKD_FALSE REPL_POLICIES REPL_OBJS REPL_LIBS ENABLE_PINGER_TRUE ENABLE_PINGER_FALSE USE_DELAY_POOLS_TRUE USE_DELAY_POOLS_FALSE USE_ICAP_TRUE USE_ICAP_FALSE USE_SNMP_TRUE USE_SNMP_FALSE SNMPLIB makesnmplib ENABLE_HTCP_TRUE ENABLE_HTCP_FALSE ENABLE_SSL_TRUE ENABLE_SSL_FALSE NEED_OWN_MD5_TRUE NEED_OWN_MD5_FALSE SSLLIB ERR_DEFAULT_LANGUAGE ERR_LANGUAGES MAKE_LEAKFINDER_TRUE MAKE_LEAKFINDER_FALSE USE_DNSSERVER_TRUE USE_DNSSERVER_FALSE OPT_DEFAULT_HOSTS AUTH_MODULES AUTH_OBJS AUTH_LIBS BASIC_AUTH_HELPERS NTLM_AUTH_HELPERS DIGEST_AUTH_HELPERS NEGOTIATE_AUTH_HELPERS EXTERNAL_ACL_HELPERS CPP EGREP LIBSASL ENABLE_UNLINKD_TRUE ENABLE_UNLINKD_FALSE RANLIB ac_ct_RANLIB LN_S SH FALSE TRUE RM MV MKDIR LN PERL AR AR_R ALLOCA CRYPTLIB LIB_EPOLL LIB_LDAP LIB_LBER LIB_DB EPOLL_LIBS USE_POLL_TRUE USE_POLL_FALSE USE_EPOLL_TRUE USE_EPOLL_FALSE USE_SELECT_TRUE USE_SELECT_FALSE USE_SELECT_WIN32_TRUE USE_SELECT_WIN32_FALSE USE_KQUEUE_TRUE USE_KQUEUE_FALSE NEED_OWN_SNPRINTF_TRUE NEED_OWN_SNPRINTF_FALSE NEED_OWN_STRNSTR_TRUE NEED_OWN_STRNSTR_FALSE NEED_OWN_STRCASESTR_TRUE NEED_OWN_STRCASESTR_FALSE NEED_OWN_STRSEP_TRUE NEED_OWN_STRSEP_FALSE REGEXLIB LIBREGEX LIBOBJS XTRA_OBJS XTRA_LIBS LTLIBOBJS'
+ ac_subst_files=''
+
+ # Initialize some variables set by options.
+@@ -890,6 +890,7 @@
+ to build your custom policy
+ --enable-icmp Enable ICMP pinging
+ --enable-delay-pools Enable delay pools to limit bandwidth usage
++ --enable-icap-support Enable ICAP client capability
+ --enable-useragent-log Enable logging of User-Agent header
+ --enable-referer-log Enable logging of Referer header
+ --disable-wccp Disable Web Cache Coordination V1 Protocol
+@@ -3843,6 +3844,40 @@
+ fi;
+
+
++
++if false; then
++ USE_ICAP_TRUE=
++ USE_ICAP_FALSE='#'
++else
++ USE_ICAP_TRUE='#'
++ USE_ICAP_FALSE=
++fi
++
++# Check whether --enable-icap-support or --disable-icap-support was given.
++if test "${enable_icap_support+set}" = set; then
++ enableval="$enable_icap_support"
++ if test "$enableval" = "yes" ; then
++ echo "ICAP support enabled"
++
++cat >>confdefs.h <<\_ACEOF
++#define HS_FEAT_ICAP 1
++_ACEOF
++
++
++
++if true; then
++ USE_ICAP_TRUE=
++ USE_ICAP_FALSE='#'
++else
++ USE_ICAP_TRUE='#'
++ USE_ICAP_FALSE=
++fi
++
++ fi
++
++fi;
++
++
+ # Check whether --enable-useragent-log or --disable-useragent-log was given.
+ if test "${enable_useragent_log+set}" = set; then
+ enableval="$enable_useragent_log"
+@@ -15688,6 +15725,8 @@
+ srand48 \
+ srandom \
+ statfs \
++ strnstr \
++ strcasestr \
+ strsep \
+ strtoll \
+ sysconf \
+@@ -16247,6 +16286,52 @@
+
+
+ if false; then
++ NEED_OWN_STRNSTR_TRUE=
++ NEED_OWN_STRNSTR_FALSE='#'
++else
++ NEED_OWN_STRNSTR_TRUE='#'
++ NEED_OWN_STRNSTR_FALSE=
++fi
++
++if test "$ac_cv_func_strnstr" = "no" || test "$ac_cv_func_vstrnstr" = "no" ; then
++
++
++if true; then
++ NEED_OWN_STRNSTR_TRUE=
++ NEED_OWN_STRNSTR_FALSE='#'
++else
++ NEED_OWN_STRNSTR_TRUE='#'
++ NEED_OWN_STRNSTR_FALSE=
++fi
++
++fi
++
++
++
++if false; then
++ NEED_OWN_STRCASESTR_TRUE=
++ NEED_OWN_STRCASESTR_FALSE='#'
++else
++ NEED_OWN_STRCASESTR_TRUE='#'
++ NEED_OWN_STRCASESTR_FALSE=
++fi
++
++if test "$ac_cv_func_strcasestr" = "no" || test "$ac_cv_func_vstrcasestr" = "no"; then
++
++
++if true; then
++ NEED_OWN_STRCASESTR_TRUE=
++ NEED_OWN_STRCASESTR_FALSE='#'
++else
++ NEED_OWN_STRCASESTR_TRUE='#'
++ NEED_OWN_STRCASESTR_FALSE=
++fi
++
++fi
++
++
++
++if false; then
+ NEED_OWN_STRSEP_TRUE=
+ NEED_OWN_STRSEP_FALSE='#'
+ else
+@@ -17731,6 +17816,20 @@
+ Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
++if test -z "${USE_ICAP_TRUE}" && test -z "${USE_ICAP_FALSE}"; then
++ { { echo "$as_me:$LINENO: error: conditional \"USE_ICAP\" was never defined.
++Usually this means the macro was only invoked conditionally." >&5
++echo "$as_me: error: conditional \"USE_ICAP\" was never defined.
++Usually this means the macro was only invoked conditionally." >&2;}
++ { (exit 1); exit 1; }; }
++fi
++if test -z "${USE_ICAP_TRUE}" && test -z "${USE_ICAP_FALSE}"; then
++ { { echo "$as_me:$LINENO: error: conditional \"USE_ICAP\" was never defined.
++Usually this means the macro was only invoked conditionally." >&5
++echo "$as_me: error: conditional \"USE_ICAP\" was never defined.
++Usually this means the macro was only invoked conditionally." >&2;}
++ { (exit 1); exit 1; }; }
++fi
+ if test -z "${USE_SNMP_TRUE}" && test -z "${USE_SNMP_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"USE_SNMP\" was never defined.
+ Usually this means the macro was only invoked conditionally." >&5
+@@ -17878,6 +17977,34 @@
+ Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
++if test -z "${NEED_OWN_STRNSTR_TRUE}" && test -z "${NEED_OWN_STRNSTR_FALSE}"; then
++ { { echo "$as_me:$LINENO: error: conditional \"NEED_OWN_STRNSTR\" was never defined.
++Usually this means the macro was only invoked conditionally." >&5
++echo "$as_me: error: conditional \"NEED_OWN_STRNSTR\" was never defined.
++Usually this means the macro was only invoked conditionally." >&2;}
++ { (exit 1); exit 1; }; }
++fi
++if test -z "${NEED_OWN_STRNSTR_TRUE}" && test -z "${NEED_OWN_STRNSTR_FALSE}"; then
++ { { echo "$as_me:$LINENO: error: conditional \"NEED_OWN_STRNSTR\" was never defined.
++Usually this means the macro was only invoked conditionally." >&5
++echo "$as_me: error: conditional \"NEED_OWN_STRNSTR\" was never defined.
++Usually this means the macro was only invoked conditionally." >&2;}
++ { (exit 1); exit 1; }; }
++fi
++if test -z "${NEED_OWN_STRCASESTR_TRUE}" && test -z "${NEED_OWN_STRCASESTR_FALSE}"; then
++ { { echo "$as_me:$LINENO: error: conditional \"NEED_OWN_STRCASESTR\" was never defined.
++Usually this means the macro was only invoked conditionally." >&5
++echo "$as_me: error: conditional \"NEED_OWN_STRCASESTR\" was never defined.
++Usually this means the macro was only invoked conditionally." >&2;}
++ { (exit 1); exit 1; }; }
++fi
++if test -z "${NEED_OWN_STRCASESTR_TRUE}" && test -z "${NEED_OWN_STRCASESTR_FALSE}"; then
++ { { echo "$as_me:$LINENO: error: conditional \"NEED_OWN_STRCASESTR\" was never defined.
++Usually this means the macro was only invoked conditionally." >&5
++echo "$as_me: error: conditional \"NEED_OWN_STRCASESTR\" was never defined.
++Usually this means the macro was only invoked conditionally." >&2;}
++ { (exit 1); exit 1; }; }
++fi
+ if test -z "${NEED_OWN_STRSEP_TRUE}" && test -z "${NEED_OWN_STRSEP_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"NEED_OWN_STRSEP\" was never defined.
+ Usually this means the macro was only invoked conditionally." >&5
+@@ -18536,6 +18663,8 @@
+ s,@ENABLE_PINGER_FALSE@,$ENABLE_PINGER_FALSE,;t t
+ s,@USE_DELAY_POOLS_TRUE@,$USE_DELAY_POOLS_TRUE,;t t
+ s,@USE_DELAY_POOLS_FALSE@,$USE_DELAY_POOLS_FALSE,;t t
++s,@USE_ICAP_TRUE@,$USE_ICAP_TRUE,;t t
++s,@USE_ICAP_FALSE@,$USE_ICAP_FALSE,;t t
+ s,@USE_SNMP_TRUE@,$USE_SNMP_TRUE,;t t
+ s,@USE_SNMP_FALSE@,$USE_SNMP_FALSE,;t t
+ s,@SNMPLIB@,$SNMPLIB,;t t
+@@ -18599,6 +18728,10 @@
+ s,@USE_KQUEUE_FALSE@,$USE_KQUEUE_FALSE,;t t
+ s,@NEED_OWN_SNPRINTF_TRUE@,$NEED_OWN_SNPRINTF_TRUE,;t t
+ s,@NEED_OWN_SNPRINTF_FALSE@,$NEED_OWN_SNPRINTF_FALSE,;t t
++s,@NEED_OWN_STRNSTR_TRUE@,$NEED_OWN_STRNSTR_TRUE,;t t
++s,@NEED_OWN_STRNSTR_FALSE@,$NEED_OWN_STRNSTR_FALSE,;t t
++s,@NEED_OWN_STRCASESTR_TRUE@,$NEED_OWN_STRCASESTR_TRUE,;t t
++s,@NEED_OWN_STRCASESTR_FALSE@,$NEED_OWN_STRCASESTR_FALSE,;t t
+ s,@NEED_OWN_STRSEP_TRUE@,$NEED_OWN_STRSEP_TRUE,;t t
+ s,@NEED_OWN_STRSEP_FALSE@,$NEED_OWN_STRSEP_FALSE,;t t
+ s,@REGEXLIB@,$REGEXLIB,;t t
+--- include/autoconf.h.in.orig Wed Jul 12 17:00:31 2006
++++ include/autoconf.h.in Sat Aug 5 16:18:25 2006
+@@ -454,6 +454,9 @@
+ /* Define to 1 if you have the <stdlib.h> header file. */
+ #undef HAVE_STDLIB_H
+
++/* Define to 1 if you have the `strcasestr' function. */
++#undef HAVE_STRCASESTR
++
+ /* Define to 1 if you have the `strerror' function. */
+ #undef HAVE_STRERROR
+
+@@ -463,6 +466,9 @@
+ /* Define to 1 if you have the <string.h> header file. */
+ #undef HAVE_STRING_H
+
++/* Define to 1 if you have the `strnstr' function. */
++#undef HAVE_STRNSTR
++
+ /* Define to 1 if you have the `strsep' function. */
+ #undef HAVE_STRSEP
+
+@@ -587,6 +593,9 @@
+
+ /* Some systems support __va_copy */
+ #undef HAVE___VA_COPY
++
++/* Content filtering via ICAP servers. */
++#undef HS_FEAT_ICAP
+
+ /* By default (for now anyway) Squid includes options which allows the cache
+ administrator to violate the HTTP protocol specification in terms of cache
+--- lib/Makefile.in.orig Mon Jun 12 08:10:08 2006
++++ lib/Makefile.in Sat Aug 5 16:19:17 2006
+@@ -62,18 +62,21 @@
+ am__libmiscutil_a_SOURCES_DIST = Array.c base64.c getfullhostname.c \
+ hash.c heap.c html_quote.c iso3307.c md5.c radix.c rfc1035.c \
+ rfc1123.c rfc1738.c rfc2617.c safe_inet_addr.c snprintf.c \
+- splay.c Stack.c strsep.c stub_memaccount.c util.c uudecode.c
++ splay.c Stack.c strnstr.c strcasestr.c strsep.c \
++ stub_memaccount.c util.c uudecode.c
+ @NEED_OWN_MD5_TRUE@am__objects_1 = md5.$(OBJEXT)
+ @NEED_OWN_SNPRINTF_TRUE@am__objects_2 = snprintf.$(OBJEXT)
+-@NEED_OWN_STRSEP_TRUE@am__objects_3 = strsep.$(OBJEXT)
++@NEED_OWN_STRNSTR_TRUE@am__objects_3 = strnstr.$(OBJEXT)
++@NEED_OWN_STRCASESTR_TRUE@am__objects_4 = strcasestr.$(OBJEXT)
++@NEED_OWN_STRSEP_TRUE@am__objects_5 = strsep.$(OBJEXT)
+ am_libmiscutil_a_OBJECTS = Array.$(OBJEXT) base64.$(OBJEXT) \
+ getfullhostname.$(OBJEXT) hash.$(OBJEXT) heap.$(OBJEXT) \
+ html_quote.$(OBJEXT) iso3307.$(OBJEXT) $(am__objects_1) \
+ radix.$(OBJEXT) rfc1035.$(OBJEXT) rfc1123.$(OBJEXT) \
+ rfc1738.$(OBJEXT) rfc2617.$(OBJEXT) safe_inet_addr.$(OBJEXT) \
+ $(am__objects_2) splay.$(OBJEXT) Stack.$(OBJEXT) \
+- $(am__objects_3) stub_memaccount.$(OBJEXT) util.$(OBJEXT) \
+- uudecode.$(OBJEXT)
++ $(am__objects_3) $(am__objects_4) $(am__objects_5) \
++ stub_memaccount.$(OBJEXT) util.$(OBJEXT) uudecode.$(OBJEXT)
+ libmiscutil_a_OBJECTS = $(am_libmiscutil_a_OBJECTS)
+ libntlmauth_a_AR = $(AR) $(ARFLAGS)
+ libntlmauth_a_DEPENDENCIES = @LIBOBJS@
+@@ -184,6 +187,10 @@
+ NEED_OWN_MD5_TRUE = @NEED_OWN_MD5_TRUE@
+ NEED_OWN_SNPRINTF_FALSE = @NEED_OWN_SNPRINTF_FALSE@
+ NEED_OWN_SNPRINTF_TRUE = @NEED_OWN_SNPRINTF_TRUE@
++NEED_OWN_STRCASESTR_FALSE = @NEED_OWN_STRCASESTR_FALSE@
++NEED_OWN_STRCASESTR_TRUE = @NEED_OWN_STRCASESTR_TRUE@
++NEED_OWN_STRNSTR_FALSE = @NEED_OWN_STRNSTR_FALSE@
++NEED_OWN_STRNSTR_TRUE = @NEED_OWN_STRNSTR_TRUE@
+ NEED_OWN_STRSEP_FALSE = @NEED_OWN_STRSEP_FALSE@
+ NEED_OWN_STRSEP_TRUE = @NEED_OWN_STRSEP_TRUE@
+ NEGOTIATE_AUTH_HELPERS = @NEGOTIATE_AUTH_HELPERS@
+@@ -221,6 +228,8 @@
+ USE_DNSSERVER_TRUE = @USE_DNSSERVER_TRUE@
+ USE_EPOLL_FALSE = @USE_EPOLL_FALSE@
+ USE_EPOLL_TRUE = @USE_EPOLL_TRUE@
++USE_ICAP_FALSE = @USE_ICAP_FALSE@
++USE_ICAP_TRUE = @USE_ICAP_TRUE@
+ USE_KQUEUE_FALSE = @USE_KQUEUE_FALSE@
+ USE_KQUEUE_TRUE = @USE_KQUEUE_TRUE@
+ USE_POLL_FALSE = @USE_POLL_FALSE@
+@@ -275,6 +284,10 @@
+ target_alias = @target_alias@
+ @NEED_OWN_SNPRINTF_FALSE@SNPRINTFSOURCE =
+ @NEED_OWN_SNPRINTF_TRUE@SNPRINTFSOURCE = snprintf.c
++@NEED_OWN_STRNSTR_FALSE@STRNSTRSOURCE =
++@NEED_OWN_STRNSTR_TRUE@STRNSTRSOURCE = strnstr.c
++@NEED_OWN_STRCASESTR_FALSE@STRCASESTRSOURCE =
++@NEED_OWN_STRCASESTR_TRUE@STRCASESTRSOURCE = strcasestr.c
+ @NEED_OWN_STRSEP_FALSE@STRSEPSOURCE =
+ @NEED_OWN_STRSEP_TRUE@STRSEPSOURCE = strsep.c
+ @NEED_OWN_MD5_FALSE@MD5SOURCE =
+@@ -316,6 +329,8 @@
+ $(SNPRINTFSOURCE) \
+ splay.c \
+ Stack.c \
++ $(STRNSTRSOURCE) \
++ $(STRCASESTRSOURCE) \
+ $(STRSEPSOURCE) \
+ stub_memaccount.c \
+ util.c \
+@@ -430,6 +445,8 @@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snprintf.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/splay.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sspwin32.Po@am__quote@
++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strcasestr.Po@am__quote@
++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strnstr.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strsep.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stub_memaccount.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@
+--- src/Makefile.in.orig Sun Jul 30 10:56:18 2006
++++ src/Makefile.in Sat Aug 5 16:19:21 2006
+@@ -90,18 +90,20 @@
+ forward.c fqdncache.c ftp.c globals.h gopher.c helper.c htcp.c \
+ http.c HttpStatusLine.c HttpHdrCc.c HttpHdrRange.c \
+ HttpHdrContRange.c HttpHeader.c HttpHeaderTools.c HttpBody.c \
+- HttpMsg.c HttpReply.c HttpRequest.c icmp.c icp_v2.c icp_v3.c \
+- ident.c internal.c ipc.c ipcache.c leakfinder.c locrewrite.c \
+- logfile.c main.c mem.c MemPool.c MemBuf.c mime.c multicast.c \
+- neighbors.c net_db.c Packer.c pconn.c peer_digest.c \
+- peer_monitor.c peer_select.c peer_sourcehash.c peer_userhash.c \
+- protos.h redirect.c referer.c refresh.c send-announce.c \
+- snmp_core.c snmp_agent.c squid.h ssl.c ssl_support.c stat.c \
+- StatHist.c String.c stmem.c store.c store_io.c store_client.c \
+- store_digest.c store_dir.c store_key_md5.c store_log.c \
+- store_rebuild.c store_swapin.c store_swapmeta.c \
+- store_swapout.c structs.h tools.c typedefs.h unlinkd.c url.c \
+- urn.c useragent.c wais.c wccp.c wccp2.c whois.c win32.c
++ HttpMsg.c HttpReply.c HttpRequest.c icap_common.c \
++ icap_reqmod.c icap_respmod.c icap_opt.c icmp.c icp_v2.c \
++ icp_v3.c ident.c internal.c ipc.c ipcache.c leakfinder.c \
++ locrewrite.c logfile.c main.c mem.c MemPool.c MemBuf.c mime.c \
++ multicast.c neighbors.c net_db.c Packer.c pconn.c \
++ peer_digest.c peer_monitor.c peer_select.c peer_sourcehash.c \
++ peer_userhash.c protos.h redirect.c referer.c refresh.c \
++ send-announce.c snmp_core.c snmp_agent.c squid.h ssl.c \
++ ssl_support.c stat.c StatHist.c String.c stmem.c store.c \
++ store_io.c store_client.c store_digest.c store_dir.c \
++ store_key_md5.c store_log.c store_rebuild.c store_swapin.c \
++ store_swapmeta.c store_swapout.c structs.h tools.c typedefs.h \
++ unlinkd.c url.c urn.c useragent.c wais.c wccp.c wccp2.c \
++ whois.c win32.c
+ @USE_EPOLL_FALSE@@USE_KQUEUE_FALSE@@USE_POLL_FALSE@@USE_SELECT_FALSE@@USE_SELECT_WIN32_TRUE@am__objects_1 = comm_select_win32.$(OBJEXT)
+ @USE_EPOLL_FALSE@@USE_KQUEUE_FALSE@@USE_POLL_FALSE@@USE_SELECT_TRUE@am__objects_1 = comm_select.$(OBJEXT)
+ @USE_EPOLL_FALSE@@USE_KQUEUE_FALSE@@USE_POLL_TRUE@am__objects_1 = comm_poll.$(OBJEXT)
+@@ -112,12 +114,15 @@
+ @USE_DNSSERVER_FALSE@am__objects_3 = dns_internal.$(OBJEXT)
+ @USE_DNSSERVER_TRUE@am__objects_3 = dns.$(OBJEXT)
+ @ENABLE_HTCP_TRUE@am__objects_4 = htcp.$(OBJEXT)
+-@MAKE_LEAKFINDER_TRUE@am__objects_5 = leakfinder.$(OBJEXT)
+-@USE_SNMP_TRUE@am__objects_6 = snmp_core.$(OBJEXT) \
++@USE_ICAP_TRUE@am__objects_5 = icap_common.$(OBJEXT) \
++@USE_ICAP_TRUE@ icap_reqmod.$(OBJEXT) icap_respmod.$(OBJEXT) \
++@USE_ICAP_TRUE@ icap_opt.$(OBJEXT)
++@MAKE_LEAKFINDER_TRUE@am__objects_6 = leakfinder.$(OBJEXT)
++@USE_SNMP_TRUE@am__objects_7 = snmp_core.$(OBJEXT) \
+ @USE_SNMP_TRUE@ snmp_agent.$(OBJEXT)
+-@ENABLE_SSL_TRUE@am__objects_7 = ssl_support.$(OBJEXT)
+-@ENABLE_UNLINKD_TRUE@am__objects_8 = unlinkd.$(OBJEXT)
+-@ENABLE_WIN32SPECIFIC_TRUE@am__objects_9 = win32.$(OBJEXT)
++@ENABLE_SSL_TRUE@am__objects_8 = ssl_support.$(OBJEXT)
++@ENABLE_UNLINKD_TRUE@am__objects_9 = unlinkd.$(OBJEXT)
++@ENABLE_WIN32SPECIFIC_TRUE@am__objects_10 = win32.$(OBJEXT)
+ am_squid_OBJECTS = access_log.$(OBJEXT) acl.$(OBJEXT) asn.$(OBJEXT) \
+ authenticate.$(OBJEXT) cache_cf.$(OBJEXT) \
+ CacheDigest.$(OBJEXT) cache_manager.$(OBJEXT) carp.$(OBJEXT) \
+@@ -132,27 +137,27 @@
+ HttpHdrRange.$(OBJEXT) HttpHdrContRange.$(OBJEXT) \
+ HttpHeader.$(OBJEXT) HttpHeaderTools.$(OBJEXT) \
+ HttpBody.$(OBJEXT) HttpMsg.$(OBJEXT) HttpReply.$(OBJEXT) \
+- HttpRequest.$(OBJEXT) icmp.$(OBJEXT) icp_v2.$(OBJEXT) \
+- icp_v3.$(OBJEXT) ident.$(OBJEXT) internal.$(OBJEXT) \
+- ipc.$(OBJEXT) ipcache.$(OBJEXT) $(am__objects_5) \
+- locrewrite.$(OBJEXT) logfile.$(OBJEXT) main.$(OBJEXT) \
+- mem.$(OBJEXT) MemPool.$(OBJEXT) MemBuf.$(OBJEXT) \
+- mime.$(OBJEXT) multicast.$(OBJEXT) neighbors.$(OBJEXT) \
+- net_db.$(OBJEXT) Packer.$(OBJEXT) pconn.$(OBJEXT) \
+- peer_digest.$(OBJEXT) peer_monitor.$(OBJEXT) \
++ HttpRequest.$(OBJEXT) $(am__objects_5) icmp.$(OBJEXT) \
++ icp_v2.$(OBJEXT) icp_v3.$(OBJEXT) ident.$(OBJEXT) \
++ internal.$(OBJEXT) ipc.$(OBJEXT) ipcache.$(OBJEXT) \
++ $(am__objects_6) locrewrite.$(OBJEXT) logfile.$(OBJEXT) \
++ main.$(OBJEXT) mem.$(OBJEXT) MemPool.$(OBJEXT) \
++ MemBuf.$(OBJEXT) mime.$(OBJEXT) multicast.$(OBJEXT) \
++ neighbors.$(OBJEXT) net_db.$(OBJEXT) Packer.$(OBJEXT) \
++ pconn.$(OBJEXT) peer_digest.$(OBJEXT) peer_monitor.$(OBJEXT) \
+ peer_select.$(OBJEXT) peer_sourcehash.$(OBJEXT) \
+ peer_userhash.$(OBJEXT) redirect.$(OBJEXT) referer.$(OBJEXT) \
+- refresh.$(OBJEXT) send-announce.$(OBJEXT) $(am__objects_6) \
+- ssl.$(OBJEXT) $(am__objects_7) stat.$(OBJEXT) \
++ refresh.$(OBJEXT) send-announce.$(OBJEXT) $(am__objects_7) \
++ ssl.$(OBJEXT) $(am__objects_8) stat.$(OBJEXT) \
+ StatHist.$(OBJEXT) String.$(OBJEXT) stmem.$(OBJEXT) \
+ store.$(OBJEXT) store_io.$(OBJEXT) store_client.$(OBJEXT) \
+ store_digest.$(OBJEXT) store_dir.$(OBJEXT) \
+ store_key_md5.$(OBJEXT) store_log.$(OBJEXT) \
+ store_rebuild.$(OBJEXT) store_swapin.$(OBJEXT) \
+ store_swapmeta.$(OBJEXT) store_swapout.$(OBJEXT) \
+- tools.$(OBJEXT) $(am__objects_8) url.$(OBJEXT) urn.$(OBJEXT) \
++ tools.$(OBJEXT) $(am__objects_9) url.$(OBJEXT) urn.$(OBJEXT) \
+ useragent.$(OBJEXT) wais.$(OBJEXT) wccp.$(OBJEXT) \
+- wccp2.$(OBJEXT) whois.$(OBJEXT) $(am__objects_9)
++ wccp2.$(OBJEXT) whois.$(OBJEXT) $(am__objects_10)
+ nodist_squid_OBJECTS = repl_modules.$(OBJEXT) auth_modules.$(OBJEXT) \
+ store_modules.$(OBJEXT) globals.$(OBJEXT) \
+ string_arrays.$(OBJEXT)
+@@ -274,6 +279,10 @@
+ NEED_OWN_MD5_TRUE = @NEED_OWN_MD5_TRUE@
+ NEED_OWN_SNPRINTF_FALSE = @NEED_OWN_SNPRINTF_FALSE@
+ NEED_OWN_SNPRINTF_TRUE = @NEED_OWN_SNPRINTF_TRUE@
++NEED_OWN_STRCASESTR_FALSE = @NEED_OWN_STRCASESTR_FALSE@
++NEED_OWN_STRCASESTR_TRUE = @NEED_OWN_STRCASESTR_TRUE@
++NEED_OWN_STRNSTR_FALSE = @NEED_OWN_STRNSTR_FALSE@
++NEED_OWN_STRNSTR_TRUE = @NEED_OWN_STRNSTR_TRUE@
+ NEED_OWN_STRSEP_FALSE = @NEED_OWN_STRSEP_FALSE@
+ NEED_OWN_STRSEP_TRUE = @NEED_OWN_STRSEP_TRUE@
+ NEGOTIATE_AUTH_HELPERS = @NEGOTIATE_AUTH_HELPERS@
+@@ -311,6 +320,8 @@
+ USE_DNSSERVER_TRUE = @USE_DNSSERVER_TRUE@
+ USE_EPOLL_FALSE = @USE_EPOLL_FALSE@
+ USE_EPOLL_TRUE = @USE_EPOLL_TRUE@
++USE_ICAP_FALSE = @USE_ICAP_FALSE@
++USE_ICAP_TRUE = @USE_ICAP_TRUE@
+ USE_KQUEUE_FALSE = @USE_KQUEUE_FALSE@
+ USE_KQUEUE_TRUE = @USE_KQUEUE_TRUE@
+ USE_POLL_FALSE = @USE_POLL_FALSE@
+@@ -363,6 +374,8 @@
+ sharedstatedir = @sharedstatedir@
+ sysconfdir = @sysconfdir@
+ target_alias = @target_alias@
++@USE_ICAP_FALSE@ICAPSOURCE =
++@USE_ICAP_TRUE@ICAPSOURCE = icap_common.c icap_reqmod.c icap_respmod.c icap_opt.c
+ @USE_DNSSERVER_FALSE@DNSSOURCE = dns_internal.c
+ @USE_DNSSERVER_TRUE@DNSSOURCE = dns.c
+ @USE_DNSSERVER_FALSE@DNSSERVER =
+@@ -458,6 +471,7 @@
+ HttpMsg.c \
+ HttpReply.c \
+ HttpRequest.c \
++ $(ICAPSOURCE) \
+ icmp.c \
+ icp_v2.c \
+ icp_v3.c \
+@@ -768,6 +782,10 @@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/helper.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htcp.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http.Po@am__quote@
++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/icap_common.Po@am__quote@
++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/icap_opt.Po@am__quote@
++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/icap_reqmod.Po@am__quote@
++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/icap_respmod.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/icmp.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/icp_v2.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/icp_v3.Po@am__quote@
diff --git a/www/squid26/files/icap-2.6-core.patch b/www/squid26/files/icap-2.6-core.patch
new file mode 100644
index 000000000000..64af138a69db
--- /dev/null
+++ b/www/squid26/files/icap-2.6-core.patch
@@ -0,0 +1,7159 @@
+Patch 1 of 2 to integrate the icap-2_6 branch into the FreeBSD squid port.
+
+Created by Thomas-Martin Seck <tmseck@netcologne.de>.
+
+This patch only contains the parts of the original patchset that
+actually implement the ICAP client functionality. The updates to
+the build infrastructure are omitted to avoid the need to run an
+autotools bootstrap. Instead, we simulate said bootstrapping with
+a second patch, icap-2.6-bootstrap.patch.
+
+The patchset was pulled from the project's CVS repository
+at cvs.devel.squid-cache.org using
+
+cvs diff -u -b -N -kk -rZ-icap-s2_6_merge_HEAD -ricap-2_6
+
+See http://devel.squid-cache.org/icap/ for further information
+about the ICAP client project.
+
+Patch last updated: 2006-08-05
+
+Index: errors/Azerbaijani/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Azerbaijani/ERR_ICAP_FAILURE
+diff -N errors/Azerbaijani/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Azerbaijani/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Bulgarian/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Bulgarian/ERR_ICAP_FAILURE
+diff -N errors/Bulgarian/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Bulgarian/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Catalan/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Catalan/ERR_ICAP_FAILURE
+diff -N errors/Catalan/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Catalan/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Czech/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Czech/ERR_ICAP_FAILURE
+diff -N errors/Czech/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Czech/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Danish/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Danish/ERR_ICAP_FAILURE
+diff -N errors/Danish/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Danish/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Dutch/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Dutch/ERR_ICAP_FAILURE
+diff -N errors/Dutch/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Dutch/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/English/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/English/ERR_ICAP_FAILURE
+diff -N errors/English/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/English/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Estonian/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Estonian/ERR_ICAP_FAILURE
+diff -N errors/Estonian/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Estonian/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Finnish/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Finnish/ERR_ICAP_FAILURE
+diff -N errors/Finnish/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Finnish/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/French/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/French/ERR_ICAP_FAILURE
+diff -N errors/French/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/French/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/German/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/German/ERR_ICAP_FAILURE
+diff -N errors/German/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/German/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.14.1
+@@ -0,0 +1,33 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>FEHLER: Der angeforderte URL konnte nicht geholt werden</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>FEHLER</H1>
++<H2>Der angeforderte URL konnte nicht geholt werden</H2>
++<HR noshade size="1px">
++<P>
++W&auml;hrend des Versuches, den URL<BR>
++<A HREF="%U">%U</A>
++
++<BR>
++zu laden, trat der folgende Fehler auf:
++<UL>
++<LI>
++<STRONG>
++ICAP-Protokollfehler
++</STRONG>
++</UL>
++
++<P>
++<P>
++Es trat ein Problem bei der ICAP-Kommunikation auf. M&ouml;gliche Gr&uuml;nde:
++<UL>
++<LI>Nicht erreichbarer ICAP-Server
++<LI>Ung&uuml;ltige Antwort vom ICAP-Server
++
++</UL>
++</P>
++
++<P>Ihr Cache Administrator ist <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Greek/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Greek/ERR_ICAP_FAILURE
+diff -N errors/Greek/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Greek/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.12.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Hebrew/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Hebrew/ERR_ICAP_FAILURE
+diff -N errors/Hebrew/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Hebrew/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Hungarian/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Hungarian/ERR_ICAP_FAILURE
+diff -N errors/Hungarian/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Hungarian/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Italian/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Italian/ERR_ICAP_FAILURE
+diff -N errors/Italian/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Italian/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Japanese/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Japanese/ERR_ICAP_FAILURE
+diff -N errors/Japanese/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Japanese/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Korean/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Korean/ERR_ICAP_FAILURE
+diff -N errors/Korean/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Korean/ERR_ICAP_FAILURE 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Lithuanian/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Lithuanian/ERR_ICAP_FAILURE
+diff -N errors/Lithuanian/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Lithuanian/ERR_ICAP_FAILURE 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Polish/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Polish/ERR_ICAP_FAILURE
+diff -N errors/Polish/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Polish/ERR_ICAP_FAILURE 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Portuguese/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Portuguese/ERR_ICAP_FAILURE
+diff -N errors/Portuguese/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Portuguese/ERR_ICAP_FAILURE 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Romanian/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Romanian/ERR_ICAP_FAILURE
+diff -N errors/Romanian/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Romanian/ERR_ICAP_FAILURE 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Russian-1251/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Russian-1251/ERR_ICAP_FAILURE
+diff -N errors/Russian-1251/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Russian-1251/ERR_ICAP_FAILURE 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Russian-koi8-r/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Russian-koi8-r/ERR_ICAP_FAILURE
+diff -N errors/Russian-koi8-r/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Russian-koi8-r/ERR_ICAP_FAILURE 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Serbian/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Serbian/ERR_ICAP_FAILURE
+diff -N errors/Serbian/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Serbian/ERR_ICAP_FAILURE 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Simplify_Chinese/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Simplify_Chinese/ERR_ICAP_FAILURE
+diff -N errors/Simplify_Chinese/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Simplify_Chinese/ERR_ICAP_FAILURE 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Slovak/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Slovak/ERR_ICAP_FAILURE
+diff -N errors/Slovak/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Slovak/ERR_ICAP_FAILURE 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Spanish/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Spanish/ERR_ICAP_FAILURE
+diff -N errors/Spanish/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Spanish/ERR_ICAP_FAILURE 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Swedish/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Swedish/ERR_ICAP_FAILURE
+diff -N errors/Swedish/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Swedish/ERR_ICAP_FAILURE 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Traditional_Chinese/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Traditional_Chinese/ERR_ICAP_FAILURE
+diff -N errors/Traditional_Chinese/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Traditional_Chinese/ERR_ICAP_FAILURE 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Turkish/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Turkish/ERR_ICAP_FAILURE
+diff -N errors/Turkish/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Turkish/ERR_ICAP_FAILURE 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: include/util.h
+===================================================================
+RCS file: /cvsroot/squid/squid/include/util.h,v
+retrieving revision 1.13
+retrieving revision 1.13.8.1
+diff -p -u -b -r1.13 -r1.13.8.1
+--- include/util.h 12 May 2006 22:51:56 -0000 1.13
++++ include/util.h 17 May 2006 17:58:00 -0000 1.13.8.1
+@@ -123,4 +123,12 @@ double drand48(void);
+ */
+ int statMemoryAccounted(void);
+
++#ifndef HAVE_STRNSTR
++extern char *strnstr(const char *haystack, const char *needle, size_t haystacklen);
++#endif
++
++#ifndef HAVE_STRCASESTR
++extern char *strcasestr(const char *haystack, const char *needle);
++#endif
++
+ #endif /* SQUID_UTIL_H */
+Index: lib/strcasestr.c
+===================================================================
+RCS file: lib/strcasestr.c
+diff -N lib/strcasestr.c
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ lib/strcasestr.c 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,126 @@
++/* Return the offset of one string within another.
++ Copyright (C) 1994,1996,1997,1998,1999,2000 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library 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
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++/*
++ * My personal strstr() implementation that beats most other algorithms.
++ * Until someone tells me otherwise, I assume that this is the
++ * fastest implementation of strstr() in C.
++ * I deliberately chose not to comment it. You should have at least
++ * as much fun trying to understand it, as I had to write it :-).
++ *
++ * Stephen R. van den Berg, berg@pool.informatik.rwth-aachen.de */
++
++/*
++ * modified to work outside of glibc (rhorstmann, 06/04/2004)
++ */
++
++#include "config.h"
++#ifndef HAVE_STRCASESTR
++#include <ctype.h>
++
++typedef unsigned chartype;
++
++char *
++strcasestr (phaystack, pneedle)
++ const char *phaystack;
++ const char *pneedle;
++{
++ register const unsigned char *haystack, *needle;
++ register chartype b, c;
++
++ haystack = (const unsigned char *) phaystack;
++ needle = (const unsigned char *) pneedle;
++
++ b = tolower (*needle);
++ if (b != '\0')
++ {
++ haystack--; /* possible ANSI violation */
++ do
++ {
++ c = *++haystack;
++ if (c == '\0')
++ goto ret0;
++ }
++ while (tolower (c) != (int) b);
++
++ c = tolower (*++needle);
++ if (c == '\0')
++ goto foundneedle;
++ ++needle;
++ goto jin;
++
++ for (;;)
++ {
++ register chartype a;
++ register const unsigned char *rhaystack, *rneedle;
++
++ do
++ {
++ a = *++haystack;
++ if (a == '\0')
++ goto ret0;
++ if (tolower (a) == (int) b)
++ break;
++ a = *++haystack;
++ if (a == '\0')
++ goto ret0;
++shloop:
++ ;
++ }
++ while (tolower (a) != (int) b);
++
++jin: a = *++haystack;
++ if (a == '\0')
++ goto ret0;
++
++ if (tolower (a) != (int) c)
++ goto shloop;
++
++ rhaystack = haystack-- + 1;
++ rneedle = needle;
++ a = tolower (*rneedle);
++
++ if (tolower (*rhaystack) == (int) a)
++ do
++ {
++ if (a == '\0')
++ goto foundneedle;
++ ++rhaystack;
++ a = tolower (*++needle);
++ if (tolower (*rhaystack) != (int) a)
++ break;
++ if (a == '\0')
++ goto foundneedle;
++ ++rhaystack;
++ a = tolower (*++needle);
++ }
++ while (tolower (*rhaystack) == (int) a);
++
++ needle = rneedle; /* took the register-poor approach */
++
++ if (a == '\0')
++ break;
++ }
++ }
++foundneedle:
++ return (char*) haystack;
++ret0:
++ return 0;
++}
++#endif
+Index: lib/strnstr.c
+===================================================================
+RCS file: lib/strnstr.c
+diff -N lib/strnstr.c
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ lib/strnstr.c 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,52 @@
++/*
++ * Copyright (C) 2003 Nikos Mavroyanopoulos
++ *
++ * This file is part of GNUTLS.
++ *
++ * The GNUTLS library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++
++ /*
++ * DW 2003/10/17:
++ * Changed 'ssize_t' types to 'size_t'
++ */
++
++#include "config.h"
++#ifndef HAVE_STRNSTR
++#include <string.h>
++#include <util.h>
++
++char *strnstr(const char *haystack, const char *needle, size_t haystacklen)
++{
++ char *p;
++ size_t plen;
++ size_t len = strlen(needle);
++
++ if (*needle == '\0') /* everything matches empty string */
++ return (char*) haystack;
++
++ plen = haystacklen;
++ for (p = (char*) haystack; p != NULL; p = memchr(p + 1, *needle, plen-1)) {
++ plen = haystacklen - (p - haystack);
++
++ if (plen < len) return NULL;
++
++ if (strncmp(p, needle, len) == 0)
++ return (p);
++ }
++ return NULL;
++}
++#endif
+Index: src/MemBuf.c
+===================================================================
+RCS file: /cvsroot/squid/squid/src/MemBuf.c,v
+retrieving revision 1.10
+retrieving revision 1.9.10.2
+diff -p -u -b -r1.10 -r1.9.10.2
+--- src/MemBuf.c 20 May 2006 22:50:55 -0000 1.10
++++ src/MemBuf.c 26 May 2006 18:21:31 -0000 1.9.10.2
+@@ -341,3 +341,15 @@ memBufReport(MemBuf * mb)
+ assert(mb);
+ memBufPrintf(mb, "memBufReport is not yet implemented @?@\n");
+ }
++
++int
++memBufRead(int fd, MemBuf * mb)
++{
++ int len;
++ if (mb->capacity == mb->size)
++ memBufGrow(mb, SQUID_TCP_SO_RCVBUF);
++ len = FD_READ_METHOD(fd, mb->buf + mb->size, mb->capacity - mb->size);
++ if (len)
++ mb->size += len;
++ return len;
++}
+Index: src/cache_cf.c
+===================================================================
+RCS file: /cvsroot/squid/squid/src/cache_cf.c,v
+retrieving revision 1.80
+retrieving revision 1.61.4.8
+diff -p -u -b -r1.80 -r1.61.4.8
+--- src/cache_cf.c 30 Jul 2006 23:52:54 -0000 1.80
++++ src/cache_cf.c 3 Aug 2006 17:16:01 -0000 1.61.4.8
+@@ -2367,6 +2367,587 @@ check_null_body_size_t(dlink_list bodyli
+ return bodylist.head == NULL;
+ }
+
++#ifdef HS_FEAT_ICAP
++
++/***************************************************
++ * prototypes
++ */
++static int icap_service_process(icap_service * s);
++static void icap_service_init(icap_service * s);
++static void icap_service_destroy(icap_service * s);
++icap_service *icap_service_lookup(char *name);
++static int icap_class_process(icap_class * c);
++static void icap_class_destroy(icap_class * c);
++static void icap_access_destroy(icap_access * a);
++static void dump_wordlist(StoreEntry * entry, const char *name, const wordlist * list);
++static void icap_class_add(icap_class * c);
++
++/***************************************************
++ * icap_service
++ */
++
++/*
++ * example:
++ * icap_service reqmode_precache 0 icap://192.168.0.1:1344/respmod
++ */
++
++static void
++parse_icap_service_type(IcapConfig * cfg)
++{
++ char *token;
++ icap_service *A = NULL;
++ icap_service *B = NULL;
++ icap_service **T = NULL;
++
++ A = cbdataAlloc(icap_service);
++ icap_service_init(A);
++ parse_string(&A->name);
++ parse_string(&A->type_name);
++ parse_ushort(&A->bypass);
++ parse_string(&A->uri);
++ while ((token = strtok(NULL, w_space))) {
++ if (strcasecmp(token, "no-keep-alive") == 0) {
++ A->keep_alive = 0;
++ } else {
++ debug(3, 0) ("parse_peer: token='%s'\n", token);
++ self_destruct();
++ }
++ }
++ debug(3, 5) ("parse_icap_service_type (line %d): %s %s %d %s\n", config_lineno, A->name, A->type_name, A->bypass, A->name);
++ if (icap_service_process(A)) {
++ /* put into linked list */
++ for (B = cfg->service_head, T = &cfg->service_head; B; T = &B->next, B = B->next);
++ *T = A;
++ } else {
++ /* clean up structure */
++ debug(3, 0) ("parse_icap_service_type (line %d): skipping %s\n", config_lineno, A->name);
++ icap_service_destroy(A);
++ cbdataFree(A);
++ }
++
++}
++
++static void
++dump_icap_service_type(StoreEntry * e, const char *name, IcapConfig cfg)
++{
++ icap_service *current_node = NULL;
++
++ if (!cfg.service_head) {
++ storeAppendPrintf(e, "%s 0\n", name);
++ return;
++ }
++ current_node = cfg.service_head;
++
++ while (current_node) {
++ storeAppendPrintf(e, "%s %s %s %d %s", name, current_node->name, current_node->type_name, current_node->bypass, current_node->uri);
++ if (current_node->keep_alive == 0) {
++ storeAppendPrintf(e, " no-keep-alive");
++ }
++ storeAppendPrintf(e, "\n");
++ current_node = current_node->next;
++ }
++
++}
++
++static void
++free_icap_service_type(IcapConfig * cfg)
++{
++ while (cfg->service_head) {
++ icap_service *current_node = cfg->service_head;
++ cfg->service_head = current_node->next;
++ icap_service_destroy(current_node);
++ cbdataFree(current_node);
++ }
++}
++
++/*
++ * parse the raw string and cache some parts that are needed later
++ * returns 1 if everything was ok
++ */
++static int
++icap_service_process(icap_service * s)
++{
++ char *start, *end, *tempEnd;
++ char *tailp;
++ unsigned int len;
++ int port_in_uri, resource_in_uri = 0;
++ s->type = icapServiceToType(s->type_name);
++ if (s->type >= ICAP_SERVICE_MAX) {
++ debug(3, 0) ("icap_service_process (line %d): wrong service type %s\n", config_lineno, s->type_name);
++ return 0;
++ }
++ if (s->type == ICAP_SERVICE_REQMOD_PRECACHE)
++ s->method = ICAP_METHOD_REQMOD;
++ else if (s->type == ICAP_SERVICE_REQMOD_PRECACHE)
++ s->method = ICAP_METHOD_REQMOD;
++ else if (s->type == ICAP_SERVICE_REQMOD_POSTCACHE)
++ s->method = ICAP_METHOD_REQMOD;
++ else if (s->type == ICAP_SERVICE_RESPMOD_PRECACHE)
++ s->method = ICAP_METHOD_RESPMOD;
++ else if (s->type == ICAP_SERVICE_RESPMOD_POSTCACHE)
++ s->method = ICAP_METHOD_RESPMOD;
++ debug(3, 5) ("icap_service_process (line %d): type=%s\n", config_lineno, icapServiceToStr(s->type));
++ if (strncmp(s->uri, "icap://", 7) != 0) {
++ debug(3, 0) ("icap_service_process (line %d): wrong uri: %s\n", config_lineno, s->uri);
++ return 0;
++ }
++ start = s->uri + 7;
++ if ((end = strchr(start, ':')) != NULL) {
++ /* ok */
++ port_in_uri = 1;
++ debug(3, 5) ("icap_service_process (line %d): port given\n", config_lineno);
++ } else {
++ /* ok */
++ port_in_uri = 0;
++ debug(3, 5) ("icap_service_process (line %d): no port given\n", config_lineno);
++ }
++
++ if ((tempEnd = strchr(start, '/')) != NULL) {
++ /* ok */
++ resource_in_uri = 1;
++ debug(3, 5) ("icap_service_process (line %d): resource given\n", config_lineno);
++ if (end == '\0') {
++ end = tempEnd;
++ }
++ } else {
++ /* ok */
++ resource_in_uri = 0;
++ debug(3, 5) ("icap_service_process (line %d): no resource given\n", config_lineno);
++ }
++
++ tempEnd = strchr(start, '\0');
++ if (end == '\0') {
++ end = tempEnd;
++ }
++ len = end - start;
++ s->hostname = xstrndup(start, len + 1);
++ s->hostname[len] = 0;
++ debug(3, 5) ("icap_service_process (line %d): hostname=%s\n", config_lineno, s->hostname);
++ start = end;
++
++ if (port_in_uri) {
++ start++; /* skip ':' */
++ if (resource_in_uri)
++ end = strchr(start, '/');
++ else
++ end = strchr(start, '\0');
++ s->port = strtoul(start, &tailp, 0) % 65536;
++ if (tailp != end) {
++ debug(3, 0) ("icap_service_process (line %d): wrong service uri (port could not be parsed): %s\n", config_lineno, s->uri);
++ return 0;
++ }
++ debug(3, 5) ("icap_service_process (line %d): port=%d\n", config_lineno, s->port);
++ start = end;
++ } else {
++ /* no explicit ICAP port; first ask by getservbyname or default to
++ * hardwired port 1344 per ICAP specification section 4.2 */
++ struct servent *serv = getservbyname("icap", "tcp");
++ if (serv) {
++ s->port = htons(serv->s_port);
++ debug(3, 5) ("icap_service_process (line %d): default port=%d getservbyname(icap,tcp)\n", config_lineno, s->port);
++ } else {
++ s->port = 1344;
++ debug(3, 5) ("icap_service_process (line %d): default hardwired port=%d\n", config_lineno, s->port);
++ }
++ }
++
++ if (resource_in_uri) {
++ start++; /* skip '/' */
++ /* the rest is resource name */
++ end = strchr(start, '\0');
++ len = end - start;
++ if (len > 1024) {
++ debug(3, 0) ("icap_service_process (line %d): long resource name (>1024), probably wrong\n", config_lineno);
++ }
++ s->resource = xstrndup(start, len + 1);
++ s->resource[len] = 0;
++ debug(3, 5) ("icap_service_process (line %d): service=%s\n", config_lineno, s->resource);
++ }
++ /* check bypass */
++ if ((s->bypass != 0) && (s->bypass != 1)) {
++ debug(3, 0) ("icap_service_process (line %d): invalid bypass value\n", config_lineno);
++ return 0;
++ }
++ return 1;
++}
++
++/*
++ * constructor
++ */
++static void
++icap_service_init(icap_service * s)
++{
++ s->type = ICAP_SERVICE_MAX; /* means undefined */
++ s->preview = Config.icapcfg.preview_size;
++ s->opt = 0;
++ s->keep_alive = 1;
++ s->istag = StringNull;
++ s->transfer_preview = StringNull;
++ s->transfer_ignore = StringNull;
++ s->transfer_complete = StringNull;
++}
++
++/*
++ * destructor
++ * frees only strings, but don't touch the linked list
++ */
++static void
++icap_service_destroy(icap_service * s)
++{
++ xfree(s->name);
++ xfree(s->uri);
++ xfree(s->type_name);
++ xfree(s->hostname);
++ xfree(s->resource);
++ assert(s->opt == 0); /* there should be no opt request running now */
++ stringClean(&s->istag);
++ stringClean(&s->transfer_preview);
++ stringClean(&s->transfer_ignore);
++ stringClean(&s->transfer_complete);
++}
++
++icap_service *
++icap_service_lookup(char *name)
++{
++ icap_service *iter;
++ for (iter = Config.icapcfg.service_head; iter; iter = iter->next) {
++ if (!strcmp(name, iter->name)) {
++ return iter;
++ }
++ }
++ return NULL;
++}
++
++/***************************************************
++ * icap_service_list
++ */
++
++static void
++icap_service_list_add(icap_service_list ** isl, char *service_name)
++{
++ icap_service_list **iter;
++ icap_service_list *new;
++ icap_service *gbl_service;
++ int i;
++ int max_services;
++
++ new = memAllocate(MEM_ICAP_SERVICE_LIST);
++ /* Found all services with that name, and add to the array */
++ max_services = sizeof(new->services) / sizeof(icap_service *);
++ gbl_service = Config.icapcfg.service_head;
++ i = 0;
++ while (gbl_service && i < max_services) {
++ if (!strcmp(service_name, gbl_service->name))
++ new->services[i++] = gbl_service;
++ gbl_service = gbl_service->next;
++ }
++ new->nservices = i;
++
++ if (*isl) {
++ iter = isl;
++ while ((*iter)->next)
++ iter = &((*iter)->next);
++ (*iter)->next = new;
++ } else {
++ *isl = new;
++ }
++}
++
++/*
++ * free the linked list without touching references icap_service
++ */
++static void
++icap_service_list_destroy(icap_service_list * isl)
++{
++ icap_service_list *current;
++ icap_service_list *next;
++
++ current = isl;
++ while (current) {
++ next = current->next;
++ memFree(current, MEM_ICAP_SERVICE_LIST);
++ current = next;
++ }
++}
++
++/***************************************************
++ * icap_class
++ */
++static void
++parse_icap_class_type(IcapConfig * cfg)
++{
++ icap_class *s = NULL;
++
++ s = memAllocate(MEM_ICAP_CLASS);
++ parse_string(&s->name);
++ parse_wordlist(&s->services);
++
++ if (icap_class_process(s)) {
++ /* if ok, put into linked list */
++ icap_class_add(s);
++ } else {
++ /* clean up structure */
++ debug(3, 0) ("parse_icap_class_type (line %d): skipping %s\n", config_lineno, s->name);
++ icap_class_destroy(s);
++ memFree(s, MEM_ICAP_CLASS);
++ }
++}
++
++static void
++dump_icap_class_type(StoreEntry * e, const char *name, IcapConfig cfg)
++{
++ icap_class *current_node = NULL;
++ LOCAL_ARRAY(char, nom, 64);
++
++ if (!cfg.class_head) {
++ storeAppendPrintf(e, "%s 0\n", name);
++ return;
++ }
++ current_node = cfg.class_head;
++
++ while (current_node) {
++ snprintf(nom, 64, "%s %s", name, current_node->name);
++ dump_wordlist(e, nom, current_node->services);
++ current_node = current_node->next;
++ }
++}
++
++static void
++free_icap_class_type(IcapConfig * cfg)
++{
++ while (cfg->class_head) {
++ icap_class *current_node = cfg->class_head;
++ cfg->class_head = current_node->next;
++ icap_class_destroy(current_node);
++ memFree(current_node, MEM_ICAP_CLASS);
++ }
++}
++
++/*
++ * process services list, return 1, if at least one service was found
++ */
++static int
++icap_class_process(icap_class * c)
++{
++ icap_service_list *isl = NULL;
++ wordlist *iter;
++ icap_service *service;
++ /* take services list and build icap_service_list from it */
++ for (iter = c->services; iter; iter = iter->next) {
++ service = icap_service_lookup(iter->key);
++ if (service) {
++ icap_service_list_add(&isl, iter->key);
++ } else {
++ debug(3, 0) ("icap_class_process (line %d): skipping service %s in class %s\n", config_lineno, iter->key, c->name);
++ }
++ }
++
++ if (isl) {
++ c->isl = isl;
++ return 1;
++ }
++ return 0;
++}
++
++/*
++ * search for an icap_class in the global IcapConfig
++ * classes with hidden-flag are skipped
++ */
++static icap_class *
++icap_class_lookup(char *name)
++{
++ icap_class *iter;
++ for (iter = Config.icapcfg.class_head; iter; iter = iter->next) {
++ if ((!strcmp(name, iter->name)) && (!iter->hidden)) {
++ return iter;
++ }
++ }
++ return NULL;
++}
++
++/*
++ * adds an icap_class to the global IcapConfig
++ */
++static void
++icap_class_add(icap_class * c)
++{
++ icap_class *cp = NULL;
++ icap_class **t = NULL;
++ IcapConfig *cfg = &Config.icapcfg;
++ if (c) {
++ for (cp = cfg->class_head, t = &cfg->class_head; cp; t = &cp->next, cp = cp->next);
++ *t = c;
++ }
++}
++
++/*
++ * free allocated memory inside icap_class
++ */
++static void
++icap_class_destroy(icap_class * c)
++{
++ xfree(c->name);
++ wordlistDestroy(&c->services);
++ icap_service_list_destroy(c->isl);
++}
++
++/***************************************************
++ * icap_access
++ */
++
++/* format: icap_access <servicename> {allow|deny} acl, ... */
++static void
++parse_icap_access_type(IcapConfig * cfg)
++{
++ icap_access *A = NULL;
++ icap_access *B = NULL;
++ icap_access **T = NULL;
++ icap_service *s = NULL;
++ icap_class *c = NULL;
++ ushort no_class = 0;
++
++ A = memAllocate(MEM_ICAP_ACCESS);
++ parse_string(&A->service_name);
++
++ /*
++ * try to find a class with the given name first. if not found, search
++ * the services. if a service is found, create a new hidden class with
++ * only this service. this is for backward compatibility.
++ *
++ * the special classname All is allowed only in deny rules, because
++ * the class is not used there.
++ */
++ if (!strcmp(A->service_name, "None")) {
++ no_class = 1;
++ } else {
++ A->class = icap_class_lookup(A->service_name);
++ if (!A->class) {
++ s = icap_service_lookup(A->service_name);
++ if (s) {
++ c = memAllocate(MEM_ICAP_CLASS);
++ c->name = xstrdup("(hidden)");
++ c->hidden = 1;
++ wordlistAdd(&c->services, A->service_name);
++ c->isl = memAllocate(MEM_ICAP_SERVICE_LIST);
++ /* FIXME:luc: check what access do */
++ c->isl->services[0] = s;
++ c->isl->nservices = 1;
++ icap_class_add(c);
++ A->class = c;
++ } else {
++ debug(3, 0) ("parse_icap_access_type (line %d): servicename %s not found. skipping.\n", config_lineno, A->service_name);
++ memFree(A, MEM_ICAP_ACCESS);
++ return;
++ }
++ }
++ }
++
++ aclParseAccessLine(&(A->access));
++ debug(3, 5) ("parse_icap_access_type (line %d): %s\n", config_lineno, A->service_name);
++
++ /* check that All class is only used in deny rule */
++ if (no_class && A->access->allow) {
++ memFree(A, MEM_ICAP_ACCESS);
++ debug(3, 0) ("parse_icap_access (line %d): special class 'None' only allowed in deny rule. skipping.\n", config_lineno);
++ return;
++ }
++ if (A->access) {
++ for (B = cfg->access_head, T = &cfg->access_head; B; T = &B->next, B = B->next);
++ *T = A;
++ } else {
++ debug(3, 0) ("parse_icap_access_type (line %d): invalid line skipped\n", config_lineno);
++ memFree(A, MEM_ICAP_ACCESS);
++ }
++}
++
++static void
++dump_icap_access_type(StoreEntry * e, const char *name, IcapConfig cfg)
++{
++ icap_access *current_node = NULL;
++ LOCAL_ARRAY(char, nom, 64);
++
++ if (!cfg.access_head) {
++ storeAppendPrintf(e, "%s 0\n", name);
++ return;
++ }
++ current_node = cfg.access_head;
++
++ while (current_node) {
++ snprintf(nom, 64, "%s %s", name, current_node->service_name);
++ dump_acl_access(e, nom, current_node->access);
++ current_node = current_node->next;
++ }
++}
++
++static void
++free_icap_access_type(IcapConfig * cfg)
++{
++ while (cfg->access_head) {
++ icap_access *current_node = cfg->access_head;
++ cfg->access_head = current_node->next;
++ icap_access_destroy(current_node);
++ memFree(current_node, MEM_ICAP_ACCESS);
++ }
++}
++
++/*
++ * destructor
++ * frees everything but the linked list
++ */
++static void
++icap_access_destroy(icap_access * a)
++{
++ xfree(a->service_name);
++ aclDestroyAccessList(&a->access);
++}
++
++/***************************************************
++ * for debugging purposes only
++ */
++void
++dump_icap_config(IcapConfig * cfg)
++{
++ icap_service *s_iter;
++ icap_class *c_iter;
++ icap_access *a_iter;
++ icap_service_list *isl_iter;
++ acl_list *l;
++ debug(3, 0) ("IcapConfig: onoff = %d\n", cfg->onoff);
++ debug(3, 0) ("IcapConfig: service_head = %d\n", (int) cfg->service_head);
++ debug(3, 0) ("IcapConfig: class_head = %d\n", (int) cfg->class_head);
++ debug(3, 0) ("IcapConfig: access_head = %d\n", (int) cfg->access_head);
++
++ debug(3, 0) ("IcapConfig: services =\n");
++ for (s_iter = cfg->service_head; s_iter; s_iter = s_iter->next) {
++ printf(" %s: \n", s_iter->name);
++ printf(" bypass = %d\n", s_iter->bypass);
++ printf(" hostname = %s\n", s_iter->hostname);
++ printf(" port = %d\n", s_iter->port);
++ printf(" resource = %s\n", s_iter->resource);
++ }
++ debug(3, 0) ("IcapConfig: classes =\n");
++ for (c_iter = cfg->class_head; c_iter; c_iter = c_iter->next) {
++ printf(" %s: \n", c_iter->name);
++ printf(" services = \n");
++ for (isl_iter = c_iter->isl; isl_iter; isl_iter = isl_iter->next) {
++ int i;
++ for (i = 0; i < isl_iter->nservices; i++)
++ printf(" %s\n", isl_iter->services[i]->name);
++ }
++ }
++ debug(3, 0) ("IcapConfig: access =\n");
++ for (a_iter = cfg->access_head; a_iter; a_iter = a_iter->next) {
++ printf(" service_name = %s\n", a_iter->service_name);
++ printf(" access = %s", a_iter->access->allow ? "allow" : "deny");
++ for (l = a_iter->access->acl_list; l != NULL; l = l->next) {
++ printf(" %s%s",
++ l->op ? null_string : "!",
++ l->acl->name);
++ }
++ printf("\n");
++ }
++}
++#endif /* HS_FEAT_ICAP */
+
+ static void
+ parse_kb_size_t(squid_off_t * var)
+Index: src/cbdata.c
+===================================================================
+RCS file: /cvsroot/squid/squid/src/cbdata.c,v
+retrieving revision 1.18
+retrieving revision 1.18.8.1
+diff -p -u -b -r1.18 -r1.18.8.1
+--- src/cbdata.c 12 May 2006 22:51:56 -0000 1.18
++++ src/cbdata.c 17 May 2006 17:58:00 -0000 1.18.8.1
+@@ -179,6 +179,10 @@ cbdataInit(void)
+ CREATE_CBDATA(statefulhelper);
+ CREATE_CBDATA(helper_stateful_server);
+ CREATE_CBDATA(HttpStateData);
++#ifdef HS_FEAT_ICAP
++ CREATE_CBDATA(IcapStateData);
++ CREATE_CBDATA(icap_service);
++#endif
+ CREATE_CBDATA_FREE(peer, peerDestroy);
+ CREATE_CBDATA(ps_state);
+ CREATE_CBDATA(RemovalPolicy);
+Index: src/cf.data.pre
+===================================================================
+RCS file: /cvsroot/squid/squid/src/cf.data.pre,v
+retrieving revision 1.147
+retrieving revision 1.100.4.8
+diff -p -u -b -r1.147 -r1.100.4.8
+--- src/cf.data.pre 3 Aug 2006 02:53:44 -0000 1.147
++++ src/cf.data.pre 3 Aug 2006 17:16:02 -0000 1.100.4.8
+@@ -3178,7 +3178,6 @@ DOC_START
+ ensure correct results it is best to set server_persistent_connections
+ to off when using this directive in such configurations.
+ DOC_END
+-
+ NAME: reply_header_max_size
+ COMMENT: (KB)
+ TYPE: b_size_t
+@@ -3447,6 +3446,187 @@ DOC_START
+ DOC_END
+
+ COMMENT_START
++ ICAP OPTIONS
++ -----------------------------------------------------------------------------
++COMMENT_END
++
++NAME: icap_enable
++TYPE: onoff
++IFDEF: HS_FEAT_ICAP
++COMMENT: on|off
++LOC: Config.icapcfg.onoff
++DEFAULT: off
++DOC_START
++ If you want to enable the ICAP client module, set this to on.
++DOC_END
++
++NAME: icap_preview_enable
++TYPE: onoff
++IFDEF: HS_FEAT_ICAP
++COMMENT: on|off
++LOC: Config.icapcfg.preview_enable
++DEFAULT: off
++DOC_START
++ Set this to 'on' if you want to enable the ICAP preview
++ feature in Squid.
++DOC_END
++
++NAME: icap_preview_size
++TYPE: int
++IFDEF: HS_FEAT_ICAP
++LOC: Config.icapcfg.preview_size
++DEFAULT: -1
++DOC_START
++ The default size of preview data to be sent to the ICAP server.
++ -1 means no preview. This value might be overwritten on a per server
++ basis by OPTIONS requests.
++DOC_END
++
++NAME: icap_check_interval
++TYPE: int
++IFDEF: HS_FEAT_ICAP
++LOC: Config.icapcfg.check_interval
++DEFAULT: 300
++DOC_START
++ If an ICAP server does not respond, it gets marked as unreachable. Squid
++ will try again to reach it after this time.
++DOC_END
++
++NAME: icap_send_client_ip
++TYPE: onoff
++IFDEF: HS_FEAT_ICAP
++COMMENT: on|off
++LOC: Config.icapcfg.send_client_ip
++DEFAULT: off
++DOC_START
++ Allows Squid to add the "X-Client-IP" header if requested by
++ an ICAP service in it's response to OPTIONS.
++DOC_END
++
++NAME: icap_send_server_ip
++TYPE: onoff
++IFDEF: HS_FEAT_ICAP
++COMMENT: on|off
++LOC: Config.icapcfg.send_server_ip
++DEFAULT: off
++DOC_START
++ Allows Squid to add the "X-Server-IP" header if requested by
++ an ICAP service in it's response to OPTIONS.
++DOC_END
++
++NAME: icap_send_auth_user
++TYPE: onoff
++IFDEF: HS_FEAT_ICAP
++COMMENT: on|off
++LOC: Config.icapcfg.send_auth_user
++DEFAULT: off
++DOC_START
++ Allows Squid to add the "X-Authenticated-User" header if requested
++ by an ICAP service in it's response to OPTIONS.
++DOC_END
++
++NAME: icap_auth_scheme
++TYPE: string
++IFDEF: HS_FEAT_ICAP
++LOC: Config.icapcfg.auth_scheme
++DEFAULT: Local://%u
++DOC_START
++ Authentification scheme to pass to ICAP requests if
++ icap_send_auth_user is enabled. The first occurence of "%u"
++ is replaced by the authentified user name. If no "%u" is found,
++ the username is added at the end of the scheme.
++
++ See http://www.ietf.org/internet-drafts/draft-stecher-icap-subid-00.txt,
++ section 3.4 for details on this.
++
++ Examples:
++
++ icap_auth_scheme Local://%u
++ icap_auth_scheme LDAP://ldap-server/cn=%u,dc=company,dc=com
++ icap_auth_scheme WinNT://nt-domain/%u
++ icap_auth_scheme Radius://radius-server/%u
++DOC_END
++
++NAME: icap_service
++TYPE: icap_service_type
++IFDEF: HS_FEAT_ICAP
++LOC: Config.icapcfg
++DEFAULT: none
++DOC_START
++ Defines a single ICAP service
++
++ icap_service servicename vectoring_point bypass service_url [options ...]
++
++ vectoring_point = reqmod_precache|reqmod_postcache|respmod_precache|respmod_postcache
++ This specifies at which point of request processing the ICAP
++ service should be plugged in.
++ bypass = 1|0
++ If set to 1 and the ICAP server cannot be reached, the request will go
++ through without being processed by an ICAP server
++ service_url = icap://servername:port/service
++
++ Options:
++
++ no-keep-alive To always close the connection to icap server
++ after the transaction completes
++
++
++ Note: reqmod_precache and respmod_postcache is not yet implemented
++
++ Load-balancing and high availability:
++ You can obtain load-balancing and high availability by defining a
++ named service with different definitions. Then, the client
++ loops through the different entities of the service providing
++ load-balancing. If an entity is marked as unreachable, the client goes
++ one step further to the next entity: you have the high-availability.
++ See the service_1 definition below
++
++Example:
++icap_service service_1 reqmod_precache 0 icap://icap1.mydomain.net:1344/reqmod
++icap_service service_1 reqmod_precache 0 icap://icap2.mydomain.net:1344/reqmod no-keep-alive
++icap_service service_2 respmod_precache 0 icap://icap3.mydomain.net:1344/respmod
++DOC_END
++
++NAME: icap_class
++TYPE: icap_class_type
++IFDEF: HS_FEAT_ICAP
++LOC: Config.icapcfg
++DEFAULT: none
++DOC_START
++ Defines an ICAP service chain. If there are multiple services per
++ vectoring point, they are processed in the specified order.
++
++ icap_class classname servicename...
++
++Example:
++icap_class class_1 service_1 service_2
++icap class class_2 service_1 service_3
++DOC_END
++
++NAME: icap_access
++TYPE: icap_access_type
++IFDEF: HS_FEAT_ICAP
++LOC: Config.icapcfg
++DEFAULT: none
++DOC_START
++ Redirects a request through an ICAP service class, depending
++ on given acls
++
++ icap_access classname allow|deny [!]aclname...
++
++ The icap_access statements are processed in the order they appear in
++ this configuration file. If an access list matches, the processing stops.
++ For an "allow" rule, the specified class is used for the request. A "deny"
++ rule simply stops processing without using the class. You can also use the
++ special classname "None".
++
++ For backward compatibility, it is also possible to use services
++ directly here.
++Example:
++icap_access class_1 allow all
++DOC_END
++
++COMMENT_START
+ MISCELLANEOUS
+ -----------------------------------------------------------------------------
+ COMMENT_END
+Index: src/cf_gen_defines
+===================================================================
+RCS file: /cvsroot/squid/squid/src/cf_gen_defines,v
+retrieving revision 1.7
+retrieving revision 1.6.8.2
+diff -p -u -b -r1.7 -r1.6.8.2
+--- src/cf_gen_defines 31 May 2006 19:51:14 -0000 1.7
++++ src/cf_gen_defines 4 Jun 2006 14:15:43 -0000 1.6.8.2
+@@ -22,6 +22,7 @@ BEGIN {
+ define["USE_WCCP"]="--enable-wccp"
+ define["USE_WCCPv2"]="--enable-wccpv2"
+ define["WIP_FWD_LOG"]="--enable-forward-log"
++ define["HS_FEAT_ICAP"]="--enable-icap-support"
+ }
+ /^IFDEF:/ {
+ if (define[$2] != "")
+Index: src/client_side.c
+===================================================================
+RCS file: /cvsroot/squid/squid/src/client_side.c,v
+retrieving revision 1.138
+retrieving revision 1.89.4.10
+diff -p -u -b -r1.138 -r1.89.4.10
+--- src/client_side.c 2 Aug 2006 21:51:40 -0000 1.138
++++ src/client_side.c 3 Aug 2006 17:16:02 -0000 1.89.4.10
+@@ -109,7 +109,7 @@ static const char *const crlf = "\r\n";
+ static CWCB clientWriteComplete;
+ static CWCB clientWriteBodyComplete;
+ static PF clientReadRequest;
+-static PF connStateFree;
++PF connStateFree;
+ static PF requestTimeout;
+ static PF clientLifetimeTimeout;
+ static int clientCheckTransferDone(clientHttpRequest *);
+@@ -141,12 +141,12 @@ static void clientSetKeepaliveFlag(clien
+ 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 *);
++void clientProcessRequest(clientHttpRequest *);
+ static void clientProcessExpired(void *data);
+ static void clientProcessOnlyIfCachedMiss(clientHttpRequest * http);
+-static int clientCachable(clientHttpRequest * http);
+-static int clientHierarchical(clientHttpRequest * http);
+-static int clientCheckContentLength(request_t * r);
++int clientCachable(clientHttpRequest * http);
++int clientHierarchical(clientHttpRequest * http);
++int clientCheckContentLength(request_t * r);
+ static DEFER httpAcceptDefer;
+ static log_type clientProcessRequest2(clientHttpRequest * http);
+ static int clientReplyBodyTooLarge(clientHttpRequest *, squid_off_t clen);
+@@ -157,14 +157,17 @@ 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;
++BODY_HANDLER clientReadBody;
+ static void clientAbortBody(request_t * req);
+ #if USE_SSL
+ static void httpsAcceptSSL(ConnStateData * connState, SSL_CTX * sslContext);
+ #endif
+ static int varyEvaluateMatch(StoreEntry * entry, request_t * request);
+ static int modifiedSince(StoreEntry *, request_t *);
+-static StoreEntry *clientCreateStoreEntry(clientHttpRequest *, method_t, request_flags);
++StoreEntry *clientCreateStoreEntry(clientHttpRequest *, method_t, request_flags);
++#if HS_FEAT_ICAP
++static int clientIcapReqMod(clientHttpRequest * http);
++#endif
+
+ #if USE_IDENT
+ static void
+@@ -382,7 +385,7 @@ clientOnlyIfCached(clientHttpRequest * h
+ EBIT_TEST(r->cache_control->mask, CC_ONLY_IF_CACHED);
+ }
+
+-static StoreEntry *
++StoreEntry *
+ clientCreateStoreEntry(clientHttpRequest * h, method_t m, request_flags flags)
+ {
+ StoreEntry *e;
+@@ -642,6 +645,10 @@ clientRedirectDone(void *data, char *res
+ if (urlgroup && *urlgroup)
+ http->request->urlgroup = xstrdup(urlgroup);
+ clientInterpretRequestHeaders(http);
++#if HS_FEAT_ICAP
++ if (Config.icapcfg.onoff)
++ icapCheckAcl(http);
++#endif
+ #if HEADERS_LOG
+ headersLog(0, 1, request->method, request);
+ #endif
+@@ -1380,11 +1387,22 @@ httpRequestFree(void *data)
+ *H = http->next;
+ http->next = NULL;
+ dlinkDelete(&http->active, &ClientActiveRequests);
++#if HS_FEAT_ICAP
++ /*In the case that the upload of data breaks, we need this code here .... */
++ if (NULL != http->icap_reqmod) {
++ if (cbdataValid(http->icap_reqmod))
++ if (http->icap_reqmod->icap_fd > -1) {
++ comm_close(http->icap_reqmod->icap_fd);
++ }
++ cbdataUnlock(http->icap_reqmod);
++ http->icap_reqmod = NULL;
++ }
++#endif
+ cbdataFree(http);
+ }
+
+ /* This is a handler normally called by comm_close() */
+-static void
++void
+ connStateFree(int fd, void *data)
+ {
+ ConnStateData *connState = data;
+@@ -1401,8 +1419,9 @@ connStateFree(int fd, void *data)
+ authenticateAuthUserRequestUnlock(connState->auth_user_request);
+ connState->auth_user_request = NULL;
+ authenticateOnCloseConnection(connState);
++ if (connState->in.buf)
+ memFreeBuf(connState->in.size, connState->in.buf);
+- pconnHistCount(0, connState->nrequests);
++/* pconnHistCount(0, connState->nrequests);*/
+ if (connState->pinning.fd >= 0)
+ comm_close(connState->pinning.fd);
+ cbdataFree(connState);
+@@ -1600,7 +1619,7 @@ clientSetKeepaliveFlag(clientHttpRequest
+ }
+ }
+
+-static int
++int
+ clientCheckContentLength(request_t * r)
+ {
+ switch (r->method) {
+@@ -1619,7 +1638,7 @@ clientCheckContentLength(request_t * r)
+ /* NOT REACHED */
+ }
+
+-static int
++int
+ clientCachable(clientHttpRequest * http)
+ {
+ request_t *req = http->request;
+@@ -1645,7 +1664,7 @@ clientCachable(clientHttpRequest * http)
+ }
+
+ /* Return true if we can query our neighbors for this object */
+-static int
++int
+ clientHierarchical(clientHttpRequest * http)
+ {
+ const char *url = http->uri;
+@@ -3350,7 +3369,7 @@ clientProcessRequest2(clientHttpRequest
+ return LOG_TCP_HIT;
+ }
+
+-static void
++void
+ clientProcessRequest(clientHttpRequest * http)
+ {
+ char *url = http->uri;
+@@ -3360,6 +3379,11 @@ clientProcessRequest(clientHttpRequest *
+ debug(33, 4) ("clientProcessRequest: %s '%s'\n",
+ RequestMethodStr[r->method],
+ url);
++#if HS_FEAT_ICAP
++ if (clientIcapReqMod(http)) {
++ return;
++ }
++#endif
+ if (r->method == METHOD_CONNECT && !http->redirect.status) {
+ http->log_type = LOG_TCP_MISS;
+ #if USE_SSL && SSL_CONNECT_INTERCEPT
+@@ -3814,6 +3838,20 @@ clientReadRequest(int fd, void *data)
+ (long) conn->in.offset, (long) conn->in.size);
+ len = conn->in.size - conn->in.offset - 1;
+ }
++#if HS_FEAT_ICAP
++ /*
++ * This check exists because ICAP doesn't always work well
++ * with persistent (reused) connections. One version of the
++ * REQMOD code creates a fake ConnStateData, which doesn't have
++ * an in.buf. We want to make sure that the fake ConnStateData
++ * doesn't get used here.
++ */
++ if (NULL == conn->in.buf) {
++ debug(33, 1) ("clientReadRequest: FD %d aborted; conn->in.buf is NULL\n", fd);
++ comm_close(fd);
++ return;
++ }
++#endif
+ statCounter.syscalls.sock.reads++;
+ size = FD_READ_METHOD(fd, conn->in.buf + conn->in.offset, len);
+ if (size > 0) {
+@@ -3917,7 +3955,8 @@ clientReadRequest(int fd, void *data)
+ /* add to the client request queue */
+ for (H = &conn->chr; *H; H = &(*H)->next);
+ *H = http;
+- conn->nrequests++;
++ F->pconn.uses++;
++ F->pconn.type = 0;
+ /*
+ * I wanted to lock 'http' here since its callback data for
+ * clientLifetimeTimeout(), but there's no logical place to
+@@ -4100,7 +4139,7 @@ clientReadRequest(int fd, void *data)
+ }
+
+ /* file_read like function, for reading body content */
+-static void
++void
+ clientReadBody(request_t * request, char *buf, size_t size, CBCB * callback, void *cbdata)
+ {
+ ConnStateData *conn = request->body_reader_data;
+@@ -4229,7 +4268,7 @@ clientProcessBody(ConnStateData * conn)
+ }
+
+ /* Abort a body request */
+-static void
++void
+ clientAbortBody(request_t * request)
+ {
+ ConnStateData *conn = request->body_reader_data;
+@@ -4271,7 +4310,7 @@ requestTimeout(int fd, void *data)
+ * Some data has been sent to the client, just close the FD
+ */
+ comm_close(fd);
+- } else if (conn->nrequests) {
++ } else if (fd_table[fd].pconn.uses) {
+ /*
+ * assume its a persistent connection; just close it
+ */
+@@ -5007,6 +5046,52 @@ varyEvaluateMatch(StoreEntry * entry, re
+ }
+ }
+
++#if HS_FEAT_ICAP
++static int
++clientIcapReqMod(clientHttpRequest * http)
++{
++ ErrorState *err;
++ icap_service *service;
++ if (http->flags.did_icap_reqmod)
++ return 0;
++ if (NULL == (service = icapService(ICAP_SERVICE_REQMOD_PRECACHE, http->request)))
++ return 0;
++ debug(33, 3) ("clientIcapReqMod: calling icapReqModStart for %p\n", http);
++ /*
++ * Note, we pass 'start' and 'log_addr' to ICAP so the access.log
++ * entry comes out right. The 'clientHttpRequest' created by
++ * the ICAP side is the one that gets logged. The first
++ * 'clientHttpRequest' does not get logged because its out.size
++ * is zero and log_type is unset.
++ */
++ http->icap_reqmod = icapReqModStart(service,
++ http->uri,
++ http->request,
++ http->conn->fd,
++ http->start,
++ http->conn->log_addr,
++ (void *) http->conn);
++ if (NULL == http->icap_reqmod) {
++ return 0;
++ } else if (-1 == (int) http->icap_reqmod) {
++ /* produce error */
++ http->icap_reqmod = NULL;
++ debug(33, 2) ("clientIcapReqMod: icap told us to send an error\n");
++ http->log_type = LOG_TCP_DENIED;
++ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
++ err->xerrno = ETIMEDOUT;
++ err->request = requestLink(http->request);
++ err->src_addr = http->conn->peer.sin_addr;
++ http->entry = clientCreateStoreEntry(http, http->request->method, null_request_flags);
++ errorAppendEntry(http->entry, err);
++ return 1;
++ }
++ cbdataLock(http->icap_reqmod);
++ http->flags.did_icap_reqmod = 1;
++ return 1;
++}
++#endif
++
+ /* This is a handler normally called by comm_close() */
+ static void
+ clientPinnedConnectionClosed(int fd, void *data)
+Index: src/comm.c
+===================================================================
+RCS file: /cvsroot/squid/squid/src/comm.c,v
+retrieving revision 1.44
+retrieving revision 1.29.10.6
+diff -p -u -b -r1.44 -r1.29.10.6
+--- src/comm.c 27 Jun 2006 11:52:53 -0000 1.44
++++ src/comm.c 28 Jun 2006 21:11:59 -0000 1.29.10.6
+@@ -736,8 +736,8 @@ comm_close(int fd)
+ F->flags.closing = 1;
+ CommWriteStateCallbackAndFree(fd, COMM_ERR_CLOSING);
+ commCallCloseHandlers(fd);
+- if (F->uses) /* assume persistent connect count */
+- pconnHistCount(1, F->uses);
++ if (F->pconn.uses)
++ pconnHistCount(F->pconn.type, F->pconn.uses);
+ #if USE_SSL
+ if (F->ssl) {
+ if (!F->flags.close_request) {
+Index: src/enums.h
+===================================================================
+RCS file: /cvsroot/squid/squid/src/enums.h,v
+retrieving revision 1.56
+retrieving revision 1.45.4.5
+diff -p -u -b -r1.56 -r1.45.4.5
+--- src/enums.h 19 Jul 2006 17:52:44 -0000 1.56
++++ src/enums.h 22 Jul 2006 14:12:01 -0000 1.45.4.5
+@@ -93,6 +93,7 @@ typedef enum {
+ ERR_ONLY_IF_CACHED_MISS, /* failure to satisfy only-if-cached request */
+ ERR_TOO_BIG,
+ TCP_RESET,
++ ERR_ICAP_FAILURE,
+ ERR_INVALID_RESP,
+ ERR_MAX
+ } err_type;
+@@ -455,6 +456,9 @@ typedef enum {
+ PROTO_WHOIS,
+ PROTO_INTERNAL,
+ PROTO_HTTPS,
++#if HS_FEAT_ICAP
++ PROTO_ICAP,
++#endif
+ PROTO_MAX
+ } protocol_t;
+
+@@ -632,6 +636,12 @@ typedef enum {
+ #if USE_SSL
+ MEM_ACL_CERT_DATA,
+ #endif
++#if HS_FEAT_ICAP
++ MEM_ICAP_OPT_DATA,
++ MEM_ICAP_SERVICE_LIST,
++ MEM_ICAP_CLASS,
++ MEM_ICAP_ACCESS,
++#endif
+ MEM_MAX
+ } mem_type;
+
+@@ -732,9 +742,14 @@ typedef enum {
+ CBDATA_RemovalPolicyWalker,
+ CBDATA_RemovalPurgeWalker,
+ CBDATA_store_client,
++#ifdef HS_FEAT_ICAP
++ CBDATA_IcapStateData,
++ CBDATA_icap_service,
++#endif
+ CBDATA_FIRST_CUSTOM_TYPE = 1000
+ } cbdata_type;
+
++
+ /*
+ * Return codes from checkVary(request)
+ */
+@@ -782,4 +797,68 @@ typedef enum {
+ ST_OP_CREATE
+ } store_op_t;
+
++#if HS_FEAT_ICAP
++typedef enum {
++ ICAP_STATUS_NONE = 0,
++ ICAP_STATUS_CONTINUE = 100,
++ ICAP_STATUS_SWITCHING_PROTOCOLS = 101,
++ ICAP_STATUS_STATUS_OK = 200,
++ ICAP_CREATED = 201,
++ ICAP_STATUS_ACCEPTED = 202,
++ ICAP_STATUS_NON_AUTHORITATIVE_INFORMATION = 203,
++ ICAP_STATUS_NO_MODIFICATION_NEEDED = 204,
++ ICAP_STATUS_RESET_CONTENT = 205,
++ ICAP_STATUS_PARTIAL_CONTENT = 206,
++ ICAP_STATUS_MULTIPLE_CHOICES = 300,
++ ICAP_STATUS_MOVED_PERMANENTLY = 301,
++ ICAP_STATUS_MOVED_TEMPORARILY = 302,
++ ICAP_STATUS_SEE_OTHER = 303,
++ ICAP_STATUS_NOT_MODIFIED = 304,
++ ICAP_STATUS_USE_PROXY = 305,
++ ICAP_STATUS_BAD_REQUEST = 400,
++ ICAP_STATUS_UNAUTHORIZED = 401,
++ ICAP_STATUS_PAYMENT_REQUIRED = 402,
++ ICAP_STATUS_FORBIDDEN = 403,
++ ICAP_STATUS_SERVICE_NOT_FOUND = 404,
++ ICAP_STATUS_METHOD_NOT_ALLOWED = 405,
++ ICAP_STATUS_NOT_ACCEPTABLE = 406,
++ ICAP_STATUS_PROXY_AUTHENTICATION_REQUIRED = 407,
++ ICAP_STATUS_REQUEST_TIMEOUT = 408,
++ ICAP_STATUS_CONFLICT = 409,
++ ICAP_STATUS_GONE = 410,
++ ICAP_STATUS_LENGTH_REQUIRED = 411,
++ ICAP_STATUS_PRECONDITION_FAILED = 412,
++ ICAP_STATUS_REQUEST_ENTITY_TOO_LARGE = 413,
++ ICAP_STATUS_REQUEST_URI_TOO_LARGE = 414,
++ ICAP_STATUS_UNSUPPORTED_MEDIA_TYPE = 415,
++ ICAP_STATUS_INTERNAL_SERVER_ERROR = 500,
++ ICAP_STATUS_NOT_IMPLEMENTED = 501,
++ ICAP_STATUS_BAD_GATEWAY = 502,
++ ICAP_STATUS_SERVICE_OVERLOADED = 503,
++ ICAP_STATUS_GATEWAY_TIMEOUT = 504,
++ ICAP_STATUS_ICAP_VERSION_NOT_SUPPORTED = 505,
++ ICAP_STATUS_INVALID_HEADER = 600
++} icap_status;
++
++/*
++ * these values are used as index in an array, so it seems to be better to
++ * assign some numbers
++ */
++typedef enum {
++ ICAP_SERVICE_REQMOD_PRECACHE = 0,
++ ICAP_SERVICE_REQMOD_POSTCACHE = 1,
++ ICAP_SERVICE_RESPMOD_PRECACHE = 2,
++ ICAP_SERVICE_RESPMOD_POSTCACHE = 3,
++ ICAP_SERVICE_MAX = 4
++} icap_service_t;
++
++typedef enum {
++ ICAP_METHOD_NONE,
++ ICAP_METHOD_OPTION,
++ ICAP_METHOD_REQMOD,
++ ICAP_METHOD_RESPMOD
++} icap_method_t;
++
++#endif /* HS_FEAT_ICAP */
++
+ #endif /* SQUID_ENUMS_H */
+Index: src/forward.c
+===================================================================
+RCS file: /cvsroot/squid/squid/src/forward.c,v
+retrieving revision 1.40
+retrieving revision 1.20.4.7
+diff -p -u -b -r1.40 -r1.20.4.7
+--- src/forward.c 30 Jun 2006 21:52:14 -0000 1.40
++++ src/forward.c 22 Jul 2006 14:12:01 -0000 1.20.4.7
+@@ -362,8 +362,9 @@ fwdConnectDone(int server_fd, int status
+ } else {
+ debug(17, 3) ("fwdConnectDone: FD %d: '%s'\n", server_fd, storeUrl(fwdState->entry));
+ fd_note(server_fd, storeUrl(fwdState->entry));
+- fd_table[server_fd].uses++;
+- if (fd_table[server_fd].uses == 1 && fs->peer)
++ fd_table[server_fd].pconn.uses++;
++ fd_table[server_fd].pconn.type = 1;
++ if (fd_table[server_fd].pconn.uses ==1 && fs->peer)
+ peerConnectSucceded(fs->peer);
+ #if USE_SSL
+ if ((fs->peer && fs->peer->use_ssl) ||
+@@ -941,6 +942,8 @@ fwdCheckDeferRead(int fd, void *data)
+ void
+ fwdFail(FwdState * fwdState, ErrorState * errorState)
+ {
++ if (NULL == fwdState)
++ return;
+ debug(17, 3) ("fwdFail: %s \"%s\"\n\t%s\n",
+ err_type_str[errorState->type],
+ httpStatusString(errorState->http_status),
+@@ -979,6 +982,8 @@ fwdPeerClosed(int fd, void *data)
+ void
+ fwdUnregister(int fd, FwdState * fwdState)
+ {
++ if (NULL == fwdState)
++ return;
+ debug(17, 3) ("fwdUnregister: %s\n", storeUrl(fwdState->entry));
+ assert(fd == fwdState->server_fd);
+ assert(fd > -1);
+@@ -998,7 +1003,10 @@ fwdUnregister(int fd, FwdState * fwdStat
+ void
+ fwdComplete(FwdState * fwdState)
+ {
+- StoreEntry *e = fwdState->entry;
++ StoreEntry *e;
++ if (NULL == fwdState)
++ return;
++ e = fwdState->entry;
+ assert(e->store_status == STORE_PENDING);
+ debug(17, 3) ("fwdComplete: %s\n\tstatus %d\n", storeUrl(e),
+ e->mem_obj->reply->sline.status);
+Index: src/globals.h
+===================================================================
+RCS file: /cvsroot/squid/squid/src/globals.h,v
+retrieving revision 1.26
+retrieving revision 1.22.4.4
+diff -p -u -b -r1.26 -r1.22.4.4
+--- src/globals.h 30 Jul 2006 23:52:54 -0000 1.26
++++ src/globals.h 3 Aug 2006 17:16:04 -0000 1.22.4.4
+@@ -171,6 +171,9 @@ extern const char *external_acl_message;
+ #if HAVE_SBRK
+ extern void *sbrk_start; /* 0 */
+ #endif
++#if HS_FEAT_ICAP
++extern char *icap_service_type_str[];
++#endif
+ extern int opt_send_signal; /* -1 */
+ extern int opt_no_daemon; /* 0 */
+ #if LINUX_TPROXY
+Index: src/http.c
+===================================================================
+RCS file: /cvsroot/squid/squid/src/http.c,v
+retrieving revision 1.47
+retrieving revision 1.28.4.9
+diff -p -u -b -r1.47 -r1.28.4.9
+--- src/http.c 26 Jul 2006 20:51:25 -0000 1.47
++++ src/http.c 3 Aug 2006 17:16:04 -0000 1.28.4.9
+@@ -47,7 +47,7 @@ static CWCB httpSendRequestEntry;
+
+ static PF httpReadReply;
+ static void httpSendRequest(HttpStateData *);
+-static PF httpStateFree;
++PF httpStateFree;
+ static PF httpTimeout;
+ static void httpCacheNegatively(StoreEntry *);
+ static void httpMakePrivate(StoreEntry *);
+@@ -56,11 +56,12 @@ static int httpCachableReply(HttpStateDa
+ static void httpMaybeRemovePublic(StoreEntry *, http_status);
+ static int peer_supports_connection_pinning(HttpStateData * httpState);
+
+-static void
++void
+ httpStateFree(int fd, void *data)
+ {
+ HttpStateData *httpState = data;
+ #if DELAY_POOLS
++ if (fd >= 0)
+ delayClearNoDelay(fd);
+ #endif
+ if (httpState == NULL)
+@@ -80,6 +81,9 @@ httpStateFree(int fd, void *data)
+ requestUnlink(httpState->orig_request);
+ httpState->request = NULL;
+ httpState->orig_request = NULL;
++#if HS_FEAT_ICAP
++ cbdataUnlock(httpState->icap_writer);
++#endif
+ cbdataFree(httpState);
+ }
+
+@@ -409,7 +413,7 @@ httpMakeVaryMark(request_t * request, Ht
+ }
+
+ /* rewrite this later using new interfaces @?@ */
+-static void
++void
+ httpProcessReplyHeader(HttpStateData * httpState, const char *buf, int size)
+ {
+ StoreEntry *entry = httpState->entry;
+@@ -551,24 +555,35 @@ httpPconnTransferDone(HttpStateData * ht
+ MemObject *mem = httpState->entry->mem_obj;
+ HttpReply *reply = mem->reply;
+ squid_off_t clen;
++ squid_off_t content_bytes_read;
+ debug(11, 3) ("httpPconnTransferDone: FD %d\n", httpState->fd);
+ debug(11, 5) ("httpPconnTransferDone: content_length=%" PRINTF_OFF_T "\n",
+ reply->content_length);
+ /* If we haven't seen the end of reply headers, we are not done */
+- if (httpState->reply_hdr_state < 2)
++ if (httpState->reply_hdr_state < 2) {
++ debug(11, 3) ("httpPconnTransferDone: reply_hdr_state=%d, returning 0\n",
++ httpState->reply_hdr_state);
+ return 0;
++ }
+ clen = httpReplyBodySize(httpState->request->method, reply);
++#ifdef HS_FEAT_ICAP
++ if (httpState->icap_writer) {
++ content_bytes_read = httpState->icap_writer->fake_content_length;
++ debug(11, 3) ("using fake conten length %" PRINTF_OFF_T "\n", content_bytes_read);
++ } else
++#endif
++ content_bytes_read = mem->inmem_hi;
+ /* If the body size is unknown we must wait for EOF */
+ if (clen < 0)
+ return 0;
+ /* Barf if we got more than we asked for */
+- if (mem->inmem_hi > clen + reply->hdr_sz)
++ if (content_bytes_read > clen + reply->hdr_sz)
+ return -1;
+ /* If there is no message body, we can be persistent */
+ if (0 == clen)
+ return 1;
+ /* If the body size is known, we must wait until we've gotten all of it. */
+- if (mem->inmem_hi < clen + reply->hdr_sz)
++ if (content_bytes_read < clen + reply->hdr_sz)
+ return 0;
+ /* We got it all */
+ return 1;
+@@ -635,6 +650,17 @@ httpReadReply(int fd, void *data)
+ delay_id delay_id;
+ #endif
+
++#if HS_FEAT_ICAP
++ if (httpState->icap_writer) {
++ if (!httpState->icap_writer->respmod.entry) {
++ debug(11, 3) ("httpReadReply: FD: %d: icap respmod aborded!\n", fd);
++ comm_close(fd);
++ return;
++ }
++ /*The folowing entry can not be marked as aborted.
++ * The StoreEntry icap_writer->respmod.entry used when the icap_write used...... */
++ } else
++#endif
+ if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
+ comm_close(fd);
+ return;
+@@ -646,7 +672,35 @@ httpReadReply(int fd, void *data)
+ else
+ delay_id = delayMostBytesAllowed(entry->mem_obj, &read_sz);
+ #endif
++#if HS_FEAT_ICAP
++ if (httpState->icap_writer) {
++ IcapStateData *icap = httpState->icap_writer;
++ /*
++ * Ok we have a received a response from the web server, so try to
++ * connect the icap server if it's the first attemps. If we try
++ * to connect to the icap server, defer this request (do not read
++ * the buffer), and defer until icapConnectOver() is not called.
++ */
++ if (icap->flags.connect_requested == 0) {
++ debug(81, 2) ("icapSendRespMod: Create a new connection to icap server\n");
++ if (!icapConnect(icap, icapConnectOver)) {
++ debug(81, 2) ("icapSendRespMod: Something strange while creating a socket to icap server\n");
++ commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
++ return;
++ }
++ debug(81, 2) ("icapSendRespMod: new connection to icap server (using FD=%d)\n", icap->icap_fd);
++ icap->flags.connect_requested = 1;
++ /* Wait for more data or EOF condition */
++ commSetTimeout(fd, httpState->flags.keepalive_broken ? 10 : Config.Timeout.read, NULL, NULL);
++ commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
++ return;
++ }
+
++ if(icap->flags.no_content == 1) {
++ commSetDefer(fd, fwdCheckDeferRead, icap->respmod.entry);
++ }
++ }
++#endif
+ errno = 0;
+ statCounter.syscalls.sock.reads++;
+ len = FD_READ_METHOD(fd, buf, read_sz);
+@@ -663,7 +717,13 @@ httpReadReply(int fd, void *data)
+ clen >>= 1;
+ IOStats.Http.read_hist[bin]++;
+ }
+- if (!httpState->reply_hdr.size && len > 0 && fd_table[fd].uses > 1) {
++#ifdef HS_FEAT_ICAP
++ if (httpState->icap_writer)
++ (void) 0;
++ else
++#endif
++
++ if (!httpState->reply_hdr.size && len > 0 && fd_table[fd].pconn.uses > 1) {
+ /* Skip whitespace */
+ while (len > 0 && xisspace(*buf))
+ xmemmove(buf, buf + 1, len--);
+@@ -693,6 +753,12 @@ httpReadReply(int fd, void *data)
+ } else if (len == 0) {
+ /* Connection closed; retrieval done. */
+ httpState->eof = 1;
++#ifdef HS_FEAT_ICAP
++ if (httpState->icap_writer && cbdataValid(httpState->icap_writer)) {
++ debug(81, 3) ("httpReadReply: EOF for ICAP writer\n");
++ icapSendRespMod(httpState->icap_writer, buf, len, 1);
++ }
++#endif
+ if (httpState->reply_hdr_state < 2)
+ /*
+ * Yes Henrik, there is a point to doing this. When we
+@@ -745,7 +811,28 @@ httpReadReply(int fd, void *data)
+ EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
+ }
+ }
++#ifdef HS_FEAT_ICAP
++ if (httpState->icap_writer) {
++ debug(81, 5) ("calling icapSendRespMod from %s:%d\n", __FILE__, __LINE__);
++ if (cbdataValid(httpState->icap_writer)) {
++ icapSendRespMod(httpState->icap_writer, buf, len, 0);
++ httpState->icap_writer->fake_content_length += len;
++ }
++ } else
++#endif
+ storeAppend(entry, buf, len);
++
++
++ debug(11, 5) ("httpReadReply: after storeAppend FD %d read %d\n", fd, len);
++#if HS_FEAT_ICAP
++ if (httpState->icap_writer) {
++ if (!httpState->icap_writer->respmod.entry) {
++ debug(11, 3) ("httpReadReply: FD: %d: icap respmod aborded!\n", fd);
++ comm_close(fd);
++ return;
++ }
++ } else
++#endif
+ if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
+ /*
+ * the above storeAppend() call could ABORT this entry,
+@@ -792,10 +879,21 @@ httpReadReply(int fd, void *data)
+ ("httpReadReply: Excess data from \"%s %s\"\n",
+ RequestMethodStr[orig_request->method],
+ storeUrl(entry));
++#ifdef HS_FEAT_ICAP
++ if (httpState->icap_writer) {
++ debug(81, 5) ("calling icapSendRespMod from %s:%d\n", __FILE__, __LINE__);
++ icapSendRespMod(httpState->icap_writer, buf, len, 0);
++ httpState->icap_writer->fake_content_length += len;
++ } else
++#endif
+ storeAppend(entry, buf, len);
+ keep_alive = 0;
+ }
+ }
++#ifdef HS_FEAT_ICAP
++ if (httpState->icap_writer)
++ icapSendRespMod(httpState->icap_writer, NULL, 0, 1);
++#endif
+ if (keep_alive) {
+ int pinned = 0;
+ #if LINUX_TPROXY
+@@ -851,6 +949,10 @@ httpReadReply(int fd, void *data)
+ ("httpReadReply: Excess data from \"%s %s\"\n",
+ RequestMethodStr[orig_request->method],
+ storeUrl(entry));
++#ifdef HS_FEAT_ICAP
++ if (httpState->icap_writer)
++ icapSendRespMod(httpState->icap_writer, NULL, 0, 1);
++#endif
+ fwdComplete(httpState->fwd);
+ comm_close(fd);
+ return;
+@@ -861,6 +963,34 @@ httpReadReply(int fd, void *data)
+ }
+ }
+
++#ifdef HS_FEAT_ICAP
++static int
++httpReadReplyWaitForIcap(int fd, void *data)
++{
++ HttpStateData *httpState = data;
++ if (NULL == httpState->icap_writer)
++ return 0;
++ /*
++ * Do not defer when we are not connected to the icap server.
++ * Defer when the icap server connection is not established but pending
++ * Defer when the icap server is busy (writing on the socket)
++ */
++ debug(11, 5) ("httpReadReplyWaitForIcap: FD %d, connect_requested=%d\n",
++ fd, httpState->icap_writer->flags.connect_requested);
++ if (!httpState->icap_writer->flags.connect_requested)
++ return 0;
++ debug(11, 5) ("httpReadReplyWaitForIcap: FD %d, connect_pending=%d\n",
++ fd, httpState->icap_writer->flags.connect_pending);
++ if (httpState->icap_writer->flags.connect_pending)
++ return 1;
++ debug(11, 5) ("httpReadReplyWaitForIcap: FD %d, write_pending=%d\n",
++ fd, httpState->icap_writer->flags.write_pending);
++ if (httpState->icap_writer->flags.write_pending)
++ return 1;
++ return 0;
++}
++#endif
++
+ /* This will be called when request write is complete. Schedule read of
+ * reply. */
+ static void
+@@ -888,6 +1018,63 @@ httpSendComplete(int fd, char *bufnotuse
+ comm_close(fd);
+ return;
+ } else {
++ /* Schedule read reply. */
++#ifdef HS_FEAT_ICAP
++ if (icapService(ICAP_SERVICE_RESPMOD_PRECACHE, httpState->orig_request)) {
++ httpState->icap_writer = icapRespModStart(
++ ICAP_SERVICE_RESPMOD_PRECACHE,
++ httpState->orig_request, httpState->entry, httpState->flags);
++ if (-1 == (int) httpState->icap_writer) {
++ /* TODO: send error here and exit */
++ ErrorState *err;
++ httpState->icap_writer = 0;
++ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
++ err->xerrno = errno;
++ err->request = requestLink(httpState->orig_request);
++ errorAppendEntry(entry, err);
++ comm_close(fd);
++ return;
++ } else if (httpState->icap_writer) {
++ request_flags fake_flags = httpState->orig_request->flags;
++ method_t fake_method = entry->mem_obj->method;
++ const char *fake_msg = "this is a fake entry for "
++ " response sent to an ICAP RESPMOD server";
++ cbdataLock(httpState->icap_writer);
++ /*
++ * this httpState will give the data it reads to
++ * the icap server, rather than put it into
++ * a StoreEntry
++ */
++ storeClientUnregisterAbort(httpState->entry);
++ storeUnlockObject(httpState->entry);
++ /*
++ * create a bogus entry because the code assumes one is
++ * always there.
++ */
++ fake_flags.cachable = 0;
++ fake_flags.hierarchical = 0; /* force private key */
++ httpState->entry = storeCreateEntry("fake", "fake", fake_flags, fake_method);
++ storeAppend(httpState->entry, fake_msg, strlen(fake_msg));
++ /*
++ * pull a switcheroo on fwdState->entry.
++ */
++ storeUnlockObject(httpState->fwd->entry);
++ httpState->fwd->entry = httpState->entry;
++ storeLockObject(httpState->fwd->entry);
++ /*
++ * Note that we leave fwdState connected to httpState,
++ * but we changed the entry. So when fwdComplete
++ * or whatever is called it does no harm -- its
++ * just the fake entry.
++ */
++ } else {
++ /*
++ * failed to open connection to ICAP server.
++ * But bypass request, so just continue here.
++ */
++ }
++ }
++#endif
+ /*
+ * Set the read timeout here because it hasn't been set yet.
+ * We only set the read timeout after the request has been
+@@ -896,8 +1083,18 @@ httpSendComplete(int fd, char *bufnotuse
+ * the timeout for POST/PUT requests that have very large
+ * request bodies.
+ */
++
++ /* removed in stable5:
++ * commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
++ */
+ commSetTimeout(fd, Config.Timeout.read, httpTimeout, httpState);
+- commSetDefer(fd, fwdCheckDeferRead, entry);
++#ifdef HS_FEAT_ICAP
++ if (httpState->icap_writer) {
++ debug(11, 5) ("FD %d, setting httpReadReplyWaitForIcap\n", httpState->fd);
++ commSetDefer(httpState->fd, httpReadReplyWaitForIcap, httpState);
++ } else
++#endif
++ commSetDefer(httpState->fd, fwdCheckDeferRead, entry);
+ }
+ httpState->flags.request_sent = 1;
+ }
+@@ -1191,8 +1388,11 @@ httpBuildRequestHeader(request_t * reque
+ if (!EBIT_TEST(cc->mask, CC_MAX_AGE)) {
+ const char *url = entry ? storeUrl(entry) : urlCanonical(orig_request);
+ httpHdrCcSetMaxAge(cc, getMaxAge(url));
++#ifndef HS_FEAT_ICAP
++ /* Don;t bother - if the url you want to cache is redirected? */
+ if (strLen(request->urlpath))
+ assert(strstr(url, strBuf(request->urlpath)));
++#endif
+ }
+ /* Set no-cache if determined needed but not found */
+ if (orig_request->flags.nocache && !httpHeaderHas(hdr_in, HDR_PRAGMA))
+@@ -1318,6 +1518,7 @@ httpStart(FwdState * fwd)
+ int fd = fwd->server_fd;
+ HttpStateData *httpState;
+ request_t *proxy_req;
++ /* ErrorState *err; */
+ request_t *orig_req = fwd->request;
+ debug(11, 3) ("httpStart: \"%s %s\"\n",
+ RequestMethodStr[orig_req->method],
+@@ -1360,12 +1561,22 @@ httpStart(FwdState * fwd)
+ httpState->request = requestLink(orig_req);
+ httpState->orig_request = requestLink(orig_req);
+ }
++#ifdef HS_FEAT_ICAP
++ if (icapService(ICAP_SERVICE_REQMOD_POSTCACHE, httpState->orig_request)) {
++ httpState->icap_writer = icapRespModStart(ICAP_SERVICE_REQMOD_POSTCACHE,
++ httpState->orig_request, httpState->entry, httpState->flags);
++ if (httpState->icap_writer) {
++ return;
++ }
++ }
++#endif
+ /*
+ * register the handler to free HTTP state data when the FD closes
+ */
+ comm_add_close_handler(fd, httpStateFree, httpState);
+ statCounter.server.all.requests++;
+ statCounter.server.http.requests++;
++
+ httpSendRequest(httpState);
+ /*
+ * We used to set the read timeout here, but not any more.
+Index: src/icap_common.c
+===================================================================
+RCS file: src/icap_common.c
+diff -N src/icap_common.c
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ src/icap_common.c 26 May 2006 19:24:02 -0000 1.1.14.3
+@@ -0,0 +1,815 @@
++/*
++ * $Id$
++ *
++ * DEBUG: section 81 Internet Content Adaptation Protocol (ICAP) Client
++ * AUTHOR: Geetha Manjunath, Hewlett Packard Company
++ *
++ * 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.
++ *
++ */
++
++/* _GNU_SOURCE is required for strcasestr */
++#define _GNU_SOURCE 1
++
++#include "squid.h"
++#include "util.h"
++
++extern PF httpStateFree;
++
++#define EXPECTED_ICAP_HEADER_LEN 256
++#define ICAP_OPTIONS_REQUEST
++
++
++void
++icapInit()
++{
++#ifdef ICAP_OPTIONS_REQUEST
++ if (Config.icapcfg.onoff) {
++ icapOptInit();
++ }
++#endif
++}
++
++void
++icapClose()
++{
++ icapOptShutdown();
++}
++
++/*
++ * search for a HTTP-like header in the buffer.
++ * Note, buf must be 0-terminated
++ *
++ * This function is not very good. It should probably look for
++ * header tokens only at the start of a line, not just anywhere in
++ * the buffer.
++ */
++int
++icapFindHeader(const char *buf, const char *hdr, const char **Start,
++ const char **End)
++{
++ const char *start = NULL;
++ const char *end = NULL;
++ start = strcasestr(buf, hdr);
++ if (NULL == start)
++ return 0;
++ end = start + strcspn(start, "\r\n");
++ if (start == end)
++ return 0;
++ *Start = start;
++ *End = end;
++ return 1;
++}
++
++/*
++ * parse the contents of the encapsulated header (buffer between enc_start
++ * and enc_end) and put the result into IcapStateData
++ */
++void
++icapParseEncapsulated(IcapStateData * icap, const char *enc_start,
++ const char *enc_end)
++{
++ char *current, *end;
++
++ assert(icap);
++ assert(enc_start);
++ assert(enc_end);
++
++ current = strchr(enc_start, ':');
++ current++;
++ while (current < enc_end) {
++ while (isspace(*current))
++ current++;
++ if (!strncmp(current, "res-hdr=", 8)) {
++ current += 8;
++ icap->enc.res_hdr = strtol(current, &end, 10);
++ } else if (!strncmp(current, "req-hdr=", 8)) {
++ current += 8;
++ icap->enc.req_hdr = strtol(current, &end, 10);
++ } else if (!strncmp(current, "null-body=", 10)) {
++ current += 10;
++ icap->enc.null_body = strtol(current, &end, 10);
++ } else if (!strncmp(current, "res-body=", 9)) {
++ current += 9;
++ icap->enc.res_body = strtol(current, &end, 10);
++ } else if (!strncmp(current, "req-body=", 9)) {
++ current += 9;
++ icap->enc.req_body = strtol(current, &end, 10);
++ } else if (!strncmp(current, "opt-body=", 9)) {
++ current += 9;
++ icap->enc.opt_body = strtol(current, &end, 10);
++ } else {
++ /* invalid header */
++ debug(81, 5) ("icapParseEncapsulated: error in: %s\n", current);
++ return;
++ }
++ current = end;
++ current = strchr(current, ',');
++ if (current == NULL)
++ break;
++ else
++ current++; /* skip ',' */
++ }
++ debug(81,
++ 3) ("icapParseEncapsulated: res-hdr=%d, req-hdr=%d, null-body=%d, "
++ "res-body=%d, req-body=%d, opt-body=%d\n", icap->enc.res_hdr,
++ icap->enc.req_hdr, icap->enc.null_body, icap->enc.res_body,
++ icap->enc.req_body, icap->enc.opt_body);
++
++}
++
++icap_service *
++icapService(icap_service_t type, request_t * r)
++{
++ icap_service_list *isl_iter;
++ int is_iter;
++ int nb_unreachable = 0;
++ icap_service *unreachable_one = NULL;
++
++ debug(81, 8) ("icapService: type=%s\n", icapServiceToStr(type));
++ if (NULL == r) {
++ debug(81, 8) ("icapService: no request_t\n");
++ return NULL;
++ }
++ if (NULL == r->class) {
++ debug(81, 8) ("icapService: no class\n");
++ return NULL;
++ }
++ for (isl_iter = r->class->isl; isl_iter; isl_iter = isl_iter->next) {
++ /* TODO:luc: Do a round-robin, choose a random value ?
++ * For now, we use a simple round robin with checking is the
++ * icap server is available */
++ is_iter = isl_iter->last_service_used;
++ do {
++ is_iter = (is_iter + 1) % isl_iter->nservices;
++ debug(81, 8) ("icapService: checking service %s/id=%d\n",
++ isl_iter->services[is_iter]->name, is_iter);
++ if (type == isl_iter->services[is_iter]->type) {
++ if (!isl_iter->services[is_iter]->unreachable) {
++ debug(81, 8) ("icapService: found service %s/id=%d\n",
++ isl_iter->services[is_iter]->name, is_iter);
++ isl_iter->last_service_used = is_iter;
++ return isl_iter->services[is_iter];
++ }
++ debug(81,
++ 8)
++ ("icapService: found service %s/id=%d, but it's unreachable. I don't want to use it\n",
++ isl_iter->services[is_iter]->name, is_iter);
++ unreachable_one = isl_iter->services[is_iter];
++ nb_unreachable++;
++ /* FIXME:luc: in response mod, if we return an NULL pointer, user can bypass
++ * the filter, is it normal ? */
++ }
++ } while (is_iter != isl_iter->last_service_used);
++ }
++ debug(81, 8) ("icapService: no service found\n");
++ isl_iter = r->class->isl;
++
++ if (nb_unreachable > 0) {
++ debug(81,
++ 8)
++ ("All the services are unreachable, returning an unreachable one\n");
++ return unreachable_one;
++ } else {
++ return NULL;
++ }
++}
++
++int
++icapConnect(IcapStateData * icap, CNCB * theCallback)
++{
++ int rc;
++ icap->icap_fd = pconnPop(icap->current_service->hostname,
++ icap->current_service->port, NULL, NULL, 0);
++ if (icap->icap_fd >= 0) {
++ debug(81, 3) ("icapConnect: reused pconn FD %d\n", icap->icap_fd);
++ fd_note(icap->icap_fd, icap->current_service->uri);
++ comm_add_close_handler(icap->icap_fd, icapStateFree, icap);
++ theCallback(icap->icap_fd, 0, icap);
++ return 1;
++ }
++ icap->icap_fd = comm_open(SOCK_STREAM, 0, getOutgoingAddr(NULL), 0,
++ COMM_NONBLOCKING, icap->current_service->uri);
++ debug(81, 5) ("icapConnect: new socket, FD %d, local address %s\n",
++ icap->icap_fd, inet_ntoa(getOutgoingAddr(NULL)));
++ if (icap->icap_fd < 0) {
++ icapStateFree(-1, icap); /* XXX test */
++ return 0;
++ }
++ icap->flags.connect_pending = 1;
++ /*
++ * Configure timeout and close handler before calling
++ * connect because commConnectStart() might get an error
++ * immediately and close the descriptor before it returns.
++ */
++ commSetTimeout(icap->icap_fd, Config.Timeout.connect,
++ icapConnectTimeout, icap);
++ comm_add_close_handler(icap->icap_fd, icapStateFree, icap);
++ /*
++ * This sucks. commConnectStart() may fail before returning,
++ * so lets lock the data and check its validity afterwards.
++ */
++ cbdataLock(icap);
++ commConnectStart(icap->icap_fd,
++ icap->current_service->hostname,
++ icap->current_service->port, theCallback, icap);
++ rc = cbdataValid(icap);
++ cbdataUnlock(icap);
++ debug(81, 3) ("icapConnect: returning %d\n", rc);
++ return rc;
++}
++
++IcapStateData *
++icapAllocate(void)
++{
++ IcapStateData *icap;
++
++ if (!Config.icapcfg.onoff)
++ return 0;
++
++ icap = cbdataAlloc(IcapStateData);
++ icap->icap_fd = -1;
++ icap->enc.res_hdr = -1;
++ icap->enc.res_body = -1;
++ icap->enc.req_hdr = -1;
++ icap->enc.req_body = -1;
++ icap->enc.opt_body = -1;
++ icap->enc.null_body = -1;
++ icap->chunk_size = -1;
++ memBufDefInit(&icap->icap_hdr);
++
++ debug(81, 3) ("New ICAP state\n");
++ return icap;
++}
++
++void
++icapStateFree(int fd, void *data)
++{
++ IcapStateData *icap = data;
++ debug(81, 3) ("icapStateFree: FD %d, icap %p\n", fd, icap);
++ assert(icap);
++ assert(-1 == fd || fd == icap->icap_fd);
++ if (icap->respmod.entry) {
++ /*
++ * If we got some error on this side (like ECONNRESET)
++ * we must signal the other side(s) with a storeAbort()
++ * call.
++ */
++ if (icap->respmod.entry->store_status != STORE_OK)
++ storeAbort(icap->respmod.entry);
++ storeUnlockObject(icap->respmod.entry);
++ icap->respmod.entry = NULL;
++ }
++ requestUnlink(icap->request);
++ icap->request = NULL;
++ if (!memBufIsNull(&icap->icap_hdr))
++ memBufClean(&icap->icap_hdr);
++ if (!memBufIsNull(&icap->respmod.buffer))
++ memBufClean(&icap->respmod.buffer);
++ if (!memBufIsNull(&icap->respmod.req_hdr_copy))
++ memBufClean(&icap->respmod.req_hdr_copy);
++ if (!memBufIsNull(&icap->respmod.resp_copy))
++ memBufClean(&icap->respmod.resp_copy);
++ if (!memBufIsNull(&icap->reqmod.hdr_buf))
++ memBufClean(&icap->reqmod.hdr_buf);
++ if (!memBufIsNull(&icap->reqmod.http_entity.buf))
++ memBufClean(&icap->reqmod.http_entity.buf);
++ if (!memBufIsNull(&icap->chunk_buf))
++ memBufClean(&icap->chunk_buf);
++ if (icap->httpState)
++ httpStateFree(-1, icap->httpState);
++ cbdataUnlock(icap->reqmod.client_cookie);
++ cbdataFree(icap);
++}
++
++void
++icapConnectTimeout(int fd, void *data)
++{
++ IcapStateData *icap = data;
++ debug(81, 3) ("icapConnectTimeout: FD %d, unreachable=1\n", fd);
++ assert(fd == icap->icap_fd);
++ icapOptSetUnreachable(icap->current_service);
++ comm_close(fd);
++}
++
++void
++icapReadTimeout(int fd, void *data)
++{
++ IcapStateData *icap = data;
++ assert(fd == icap->icap_fd);
++ if (icap->flags.wait_for_preview_reply || icap->flags.http_server_eof) {
++ debug(81, 3) ("icapReadTimeout: FD %d, unreachable=1\n", fd);
++ icapOptSetUnreachable(icap->current_service);
++ } else
++ debug(81, 3) ("icapReadTimeout: FD %d, still reachable\n", fd);
++ comm_close(fd);
++}
++
++icap_service_t
++icapServiceToType(const char *s)
++{
++ if (!strcmp(s, "reqmod_precache"))
++ return ICAP_SERVICE_REQMOD_PRECACHE;
++ if (!strcmp(s, "reqmod_postcache"))
++ return ICAP_SERVICE_REQMOD_POSTCACHE;
++ if (!strcmp(s, "respmod_precache"))
++ return ICAP_SERVICE_RESPMOD_PRECACHE;
++ if (!strcmp(s, "respmod_postcache"))
++ return ICAP_SERVICE_RESPMOD_POSTCACHE;
++ return ICAP_SERVICE_MAX;
++}
++
++const char *
++icapServiceToStr(const icap_service_t type)
++{
++ if (type >= 0 && type < ICAP_SERVICE_MAX)
++ return icap_service_type_str[type];
++ else
++ return "error";
++}
++
++
++/* copied from clientAclChecklistCreate */
++static aclCheck_t *
++icapAclChecklistCreate(const acl_access * acl, const clientHttpRequest * http)
++{
++ aclCheck_t *ch;
++ ConnStateData *conn = http->conn;
++ ch = aclChecklistCreate(acl, http->request, 0);
++ ch->conn = conn;
++ cbdataLock(ch->conn);
++ return ch;
++}
++
++/*
++ * check wether we do icap for a request
++ */
++int
++icapCheckAcl(clientHttpRequest * http)
++{
++ icap_access *iter;
++ aclCheck_t *icapChecklist;
++
++ for (iter = Config.icapcfg.access_head; iter; iter = iter->next) {
++ acl_access *A = iter->access;
++ icapChecklist = icapAclChecklistCreate(A, http);
++ if (aclMatchAclList(A->acl_list, icapChecklist)) {
++ debug(81, 5) ("icapCheckAcl: match for class=%s\n",
++ iter->class->name);
++ if (A->allow) {
++ /* allow rule, do icap and use associated class */
++ http->request->class = iter->class;
++ aclChecklistFree(icapChecklist);
++ return 1;
++ } else {
++ /* deny rule, stop processing */
++ aclChecklistFree(icapChecklist);
++ return 0;
++ }
++ }
++ aclChecklistFree(icapChecklist);
++ }
++ return 0;
++}
++
++/* icapLineLength
++ *
++ * returns the amount of data until lineending ( \r\n )
++ * This function is NOT tolerant of variations of \r\n.
++ */
++size_t
++icapLineLength(const char *start, int len)
++{
++ size_t lineLen = 0;
++ char *end = (char *) memchr(start, '\r', len);
++ if (NULL == end)
++ return 0;
++ end++; /* advance to where '\n' should be */
++ lineLen = end - start + 1;
++ if (lineLen > len) {
++ debug(0, 0) ("icapLineLength: warning lineLen (%d) > len (%d)\n",
++ lineLen, len);
++ return 0;
++ }
++ if (*end != '\n') {
++ debug(0, 0) ("icapLineLength: warning *end (%x) != '\\n'\n", *end);
++ return 0;
++ }
++ debug(81, 7) ("icapLineLength: returning %d\n", lineLen);
++ return lineLen;
++}
++
++/*
++ * return:
++ * -1 if EOF before getting end of ICAP header
++ * 0 if we don't have the entire ICAP header yet
++ * 1 if we got the whole header
++ */
++int
++icapReadHeader(int fd, IcapStateData * icap, int *isIcap)
++{
++ int headlen = 0;
++ int len = 0;
++ int peek_sz = EXPECTED_ICAP_HEADER_LEN;
++ int read_sz = 0;
++ LOCAL_ARRAY(char, tmpbuf, SQUID_TCP_SO_RCVBUF);
++ for (;;) {
++ len = recv(fd, tmpbuf, peek_sz, MSG_PEEK);
++ debug(81, 5) ("recv(FD %d, ..., MSG_PEEK) ret %d\n", fd, len);
++ if (len < 0) {
++ debug(81, 1) ("icapReadHeader: FD %d recv error: %s\n", fd,
++ xstrerror());
++ return -1;
++ }
++ if (len == 0) {
++ debug(81, 2) ("icapReadHeader: FD %d recv EOF\n", fd);
++ return -1;
++ }
++ headlen = headersEnd(tmpbuf, len);
++ debug(81, 3) ("headlen=%d\n", headlen);
++ /*
++ * break if we now know where the ICAP headers end
++ */
++ if (headlen)
++ break;
++ /*
++ * break if we know there is no more data to read
++ */
++ if (len < peek_sz)
++ break;
++ /*
++ * The ICAP header is larger than (or equal to) our read
++ * buffer, so double it and try to peek again.
++ */
++ peek_sz *= 2;
++ if (peek_sz >= SQUID_TCP_SO_RCVBUF) {
++ debug(81,
++ 1) ("icapReadHeader: Failed to find end of ICAP header\n");
++ debug(81, 1) ("\twithin first %d bytes of response\n",
++ SQUID_TCP_SO_RCVBUF);
++ debug(81, 1) ("\tpossible persistent connection bug/confusion\n");
++ return -1;
++ }
++ }
++ /*
++ * Now actually read the data from the kernel
++ */
++ if (headlen)
++ read_sz = headlen;
++ else
++ read_sz = len;
++ len = FD_READ_METHOD(fd, tmpbuf, read_sz);
++ assert(len == read_sz);
++ fd_bytes(fd, len, FD_READ);
++ memBufAppend(&icap->icap_hdr, tmpbuf, len);
++ if (headlen) {
++ /* End of ICAP header found */
++ if (icap->icap_hdr.size < 4)
++ *isIcap = 0;
++ else if (0 == strncmp(icap->icap_hdr.buf, "ICAP", 4))
++ *isIcap = 1;
++ else
++ *isIcap = 0;
++ return 1;
++ }
++ /*
++ * We don't have all the headers yet
++ */
++ return 0;
++}
++
++static int
++icapParseConnectionClose(const IcapStateData * icap, const char *s,
++ const char *e)
++{
++ char *t;
++ char *q;
++ /*
++ * s points to the start of the line "Connection: ... "
++ * e points to *after* the last character on the line
++ */
++ s += 11; /* skip past Connection: */
++ while (s < e && isspace(*s))
++ s++;
++ if (e - s < 5)
++ return 0;
++ /*
++ * create a buffer that we can use strtok on
++ */
++ t = xmalloc(e - s + 1);
++ strncpy(t, s, e - s);
++ *(t + (e - s)) = '\0';
++ for (q = strtok(t, ","); q; q = strtok(NULL, ",")) {
++ if (0 == strcasecmp(q, "close")) {
++ xfree(t);
++ return 1;
++ }
++ }
++ xfree(t);
++ return 0;
++}
++
++/* returns icap status, version and subversion extracted from status line or -1 on parsing failure
++ * The str_status pointr points to the text returned from the icap server.
++ * sline probably is NOT terminated with '\0'
++ */
++int
++icapParseStatusLine(const char *sline, int slinesize, int *version_major,
++ int *version_minor, const char **str_status)
++{
++ char *sp, *stmp, *ep = (char *) sline + slinesize;
++ int status;
++ if (slinesize < 14) /*The format of this line is: "ICAP/x.x xxx[ msg....]\r\n" */
++ return -1;
++
++ if (strncmp(sline, "ICAP/", 5) != 0)
++ return -1;
++ if (sscanf(sline + 5, "%d.%d", version_major, version_minor) != 2)
++ return -1;
++
++ if (!(sp = memchr(sline, ' ', slinesize)))
++ return -1;
++
++ while (sp < ep && xisspace(*++sp));
++
++ if (!xisdigit(*sp) || sp >= ep)
++ return -1;
++
++ if ((status = strtol(sp, &stmp, 10)) <= 0)
++ return -1;
++ sp = stmp;
++
++ while (sp < ep && xisspace(*++sp));
++ *str_status = sp;
++ /*Must add a test for "\r\n" end headers .... */
++ return status;
++}
++
++
++void
++icapSetKeepAlive(IcapStateData * icap, const char *hdrs)
++{
++ const char *start;
++ const char *end;
++ if (0 == icap->flags.keep_alive)
++ return;
++ if (0 == icapFindHeader(hdrs, "Connection:", &start, &end)) {
++ icap->flags.keep_alive = 1;
++ return;
++ }
++ if (icapParseConnectionClose(icap, start, end))
++ icap->flags.keep_alive = 0;
++ else
++ icap->flags.keep_alive = 1;
++}
++
++/*
++ * icapParseChunkSize
++ *
++ * Returns the offset where the next chunk starts
++ * return parameter chunk_size;
++ */
++static int
++icapParseChunkSize(const char *buf, int len, int *chunk_size)
++{
++ int chunkSize = 0;
++ char c;
++ size_t start;
++ size_t end;
++ size_t nextStart = 0;
++ debug(81, 3) ("icapParseChunkSize: buf=%p, len=%d\n", buf, len);
++ do {
++ start = nextStart;
++ debug(81, 3) ("icapParseChunkSize: start=%d\n", start);
++ if (len <= start) {
++ /*
++ * end of buffer, so far no lines or only empty lines,
++ * wait for more data. read chunk size with next buffer.
++ */
++ *chunk_size = 0;
++ return 0;
++ }
++ end = start + icapLineLength(buf + start, len - start);
++ nextStart = end;
++ if (end <= start) {
++ /*
++ * no line found, need more code here, now we are in
++ * deep trouble, buffer stops with half a chunk size
++ * line. For now stop here.
++ */
++ debug(81, 1) ("icapParseChunkSize: WARNING in mid-line, ret 0\n");
++ *chunk_size = 0;
++ return 0;
++ }
++ while (start < end) {
++ if (NULL == strchr(w_space, buf[start]))
++ break;
++ start++;
++ }
++ while (start < end) {
++ if (NULL == strchr(w_space, buf[end - 1]))
++ break;
++ end--;
++ }
++ /*
++ * if now end <= start we got an empty line. The previous
++ * chunk data should stop with a CRLF. In case that the
++ * other end does not follow the specs and sends no CRLF
++ * or too many empty lines, just continue till we have a
++ * non-empty line.
++ */
++ } while (end <= start);
++ debug(81, 3) ("icapParseChunkSize: start=%d, end=%d\n", start, end);
++
++ /* Non-empty line: Parse the chunk size */
++ while (start < end) {
++ c = buf[start++];
++ if (c >= 'a' && c <= 'f') {
++ chunkSize = chunkSize * 16 + c - 'a' + 10;
++ } else if (c >= 'A' && c <= 'F') {
++ chunkSize = chunkSize * 16 + c - 'A' + 10;
++ } else if (c >= '0' && c <= '9') {
++ chunkSize = chunkSize * 16 + c - '0';
++ } else {
++ if (!(c == ';' || c == ' ' || c == '\t')) {
++ /*Syntax error: Chunksize expected. */
++ *chunk_size = -2; /* we are done */
++ return nextStart;
++ }
++ /* Next comes a chunk extension */
++ break;
++ }
++ }
++ /*
++ * if we read a zero chunk, we reached the end. Mark this for
++ * icapPconnTransferDone
++ */
++ *chunk_size = (chunkSize > 0) ? chunkSize : -2;
++ debug(81, 3) ("icapParseChunkSize: return nextStart=%d\n", nextStart);
++ return nextStart;
++}
++
++/*
++ * icapParseChunkedBody
++ *
++ * De-chunk an HTTP entity received from the ICAP server.
++ * The 'store' function pointer is storeAppend() or memBufAppend().
++ */
++size_t
++icapParseChunkedBody(IcapStateData * icap, STRCB * store, void *store_data)
++{
++ int bufOffset = 0;
++ size_t bw = 0;
++ MemBuf *cb = &icap->chunk_buf;
++ const char *buf = cb->buf;
++ int len = cb->size;
++
++ if (icap->chunk_size == -2) {
++ debug(81, 3) ("zero end chunk reached\n");
++ return 0;
++ }
++ debug(81, 3) ("%s:%d: chunk_size=%d\n", __FILE__, __LINE__,
++ icap->chunk_size);
++ if (icap->chunk_size < 0) {
++ store(store_data, buf, len);
++ cb->size = 0;
++ return (size_t) len;
++ }
++ debug(81, 3) ("%s:%d: bufOffset=%d, len=%d\n", __FILE__, __LINE__,
++ bufOffset, len);
++ while (bufOffset < len) {
++ debug(81, 3) ("%s:%d: bufOffset=%d, len=%d\n", __FILE__, __LINE__,
++ bufOffset, len);
++ if (icap->chunk_size == 0) {
++ int x;
++ x = icapParseChunkSize(buf + bufOffset,
++ len - bufOffset, &icap->chunk_size);
++ if (x < 1) {
++ /* didn't find a valid chunk spec */
++ break;
++ }
++ bufOffset += x;
++ debug(81, 3) ("got chunksize %d, new offset %d\n",
++ icap->chunk_size, bufOffset);
++ if (icap->chunk_size == -2) {
++ debug(81, 3) ("zero end chunk reached\n");
++ break;
++ }
++ }
++ debug(81, 3) ("%s:%d: X\n", __FILE__, __LINE__);
++ if (icap->chunk_size > 0) {
++ if (icap->chunk_size >= len - bufOffset) {
++ store(store_data, buf + bufOffset, len - bufOffset);
++ bw += (len - bufOffset);
++ icap->chunk_size -= (len - bufOffset);
++ bufOffset = len;
++ } else {
++ store(store_data, buf + bufOffset, icap->chunk_size);
++ bufOffset += icap->chunk_size;
++ bw += icap->chunk_size;
++ icap->chunk_size = 0;
++ }
++ }
++ }
++ if (0 == bufOffset) {
++ (void) 0;
++ } else if (bufOffset == cb->size) {
++ cb->size = 0;
++ } else {
++ assert(bufOffset <= cb->size);
++ xmemmove(cb->buf, cb->buf + bufOffset, cb->size - bufOffset);
++ cb->size -= bufOffset;
++ }
++ return bw;
++}
++
++/*
++ * icapAddAuthUserHeader
++ *
++ * Builds and adds the X-Authenticated-User header to an ICAP request headers.
++ */
++void
++icapAddAuthUserHeader(MemBuf * mb, auth_user_request_t * auth_user_request)
++{
++ char *user = authenticateUserRequestUsername(auth_user_request);
++ char *authuser;
++ size_t len, userlen, schemelen, userofslen;
++ char *userofs;
++
++ if (user == NULL) {
++ debug(81, 5) ("icapAddAuthUserHeader: NULL username\n");
++ return;
++ }
++ userlen = strlen(user);
++ schemelen = strlen(Config.icapcfg.auth_scheme);
++ len = userlen + schemelen + 1;
++ authuser = xcalloc(len, 1);
++
++ if ((userofs = strstr(Config.icapcfg.auth_scheme, "%u")) == NULL) {
++ /* simply add user at end of string */
++ snprintf(authuser, len, "%s%s", Config.icapcfg.auth_scheme, user);
++ } else {
++ userofslen = userofs - Config.icapcfg.auth_scheme;
++ xmemcpy(authuser, Config.icapcfg.auth_scheme, userofslen);
++ xmemcpy(authuser + userofslen, user, userlen);
++ xmemcpy(authuser + userofslen + userlen,
++ userofs + 2, schemelen - (userofslen + 2) + 1);
++ }
++
++ memBufPrintf(mb, "X-Authenticated-User: %s\r\n", base64_encode(authuser));
++ xfree(authuser);
++}
++
++/*
++ * icapAddOriginIP
++ *
++ * Builds and adds the X-Server-IP header to an ICAP request headers.
++ */
++void
++icapAddOriginIP(MemBuf * mb, const char *host)
++{
++ const ipcache_addrs *addrs;
++ struct in_addr s;
++
++ if (host == NULL) {
++ debug(81, 5) ("icapAddOriginIP: NULL host\n");
++ return;
++ }
++ addrs = ipcache_gethostbyname(host, IP_LOOKUP_IF_MISS);
++ if (addrs == NULL) {
++ /*
++ * http://www.i-cap.org/spec/draft-stecher-icap-subid-00.txt :
++ *
++ * [...] If the meta information for some header is not available,
++ * the header field MUST be omitted.
++ */
++ debug(81, 5) ("icapAddOriginIP: can't tell IP address\n");
++ return;
++ }
++ s = addrs->in_addrs[0];
++ memBufPrintf(mb, "X-Server-IP: %s\r\n", inet_ntoa(s));
++}
+Index: src/icap_opt.c
+===================================================================
+RCS file: src/icap_opt.c
+diff -N src/icap_opt.c
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ src/icap_opt.c 17 May 2006 17:58:01 -0000 1.1.16.1
+@@ -0,0 +1,523 @@
++
++/*
++ * $Id$
++ *
++ * DEBUG: section 81 Internet Content Adaptation Protocol (ICAP) Client OPTIONS
++ * AUTHOR: Ralf Horstmann
++ *
++ * 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"
++
++/*************************************************************/
++
++/*
++ * network related functions for OPTIONS request
++ */
++static void icapOptStart(void *data);
++static void icapOptTimeout(int fd, void *data);
++static void icapOptConnectDone(int server_fd, int status, void *data);
++static void icapOptWriteComplete(int fd, char *bufnotused, size_t size, int errflag, void *data);
++static void icapOptReadReply(int fd, void *data);
++
++/*
++ * reply parsing functions
++ */
++static int icapOptParseReply(icap_service * s, IcapOptData * i);
++static void icapOptParseEntry(icap_service * s, const char *blk_start, const char *blk_end);
++static int icapIsolateLine(const char **parse_start, const char **blk_start, const char **blk_end);
++
++/*
++ * helper functions
++ */
++static void icapOptDataInit(IcapOptData * i);
++static void icapOptDataFree(IcapOptData * i);
++
++/*************************************************************/
++
++#define TIMEOUT 10
++
++void
++icapOptInit()
++{
++ icap_service *s;
++
++ /* iterate over configured services */
++ s = Config.icapcfg.service_head;
++ while (s) {
++ eventAdd("icapOptStart", icapOptStart, s, 5.0, 1);
++ s = s->next;
++ }
++}
++
++void
++icapOptShutdown()
++{
++ icap_service *s;
++
++ s = Config.icapcfg.service_head;
++ while (s) {
++ if (eventFind(icapOptStart, s)) {
++ eventDelete(icapOptStart, s);
++ }
++ s = s->next;
++ }
++}
++
++/*
++ * mark a service as unreachable
++ */
++void
++icapOptSetUnreachable(icap_service * s)
++{
++ s->unreachable = 1;
++ debug(81, 5) ("icapOptSetUnreachable: got called for %s\n", s->uri);
++ /*
++ * if there is an options request scheduled, delete it and add
++ * it again to reset the time to the default check_interval.
++ */
++ if (eventFind(icapOptStart, s)) {
++ eventDelete(icapOptStart, s);
++ eventAdd("icapOptStart", icapOptStart, s, Config.icapcfg.check_interval, 1);
++ }
++}
++
++static void
++icapOptStart(void *data)
++{
++ icap_service *s = data;
++ int fd;
++ int ctimeout = TIMEOUT;
++ const char *host = s->hostname;
++ unsigned short port = s->port;
++ debug(81, 3) ("icapOptStart: starting OPTIONS request for %s (%s)\n", s->name, s->uri);
++ fd = comm_open(SOCK_STREAM,
++ 0,
++ getOutgoingAddr(NULL),
++ 0,
++ COMM_NONBLOCKING,
++ "ICAP OPTIONS connection");
++ if (fd < 0) {
++ debug(81, 4) ("icapConnectStart: %s\n", xstrerror());
++ eventAdd("icapOptStart", icapOptStart, s, Config.icapcfg.check_interval, 1);
++ return;
++ }
++ assert(s->opt == NULL); /* if not null, another options request might be running, which should not happen */
++ s->opt = memAllocate(MEM_ICAP_OPT_DATA);
++ icapOptDataInit(s->opt);
++ cbdataLock(s);
++ commSetTimeout(fd, ctimeout, icapOptTimeout, s);
++ commConnectStart(fd, host, port, icapOptConnectDone, s);
++}
++
++static void
++icapOptTimeout(int fd, void *data)
++{
++ icap_service *s = data;
++ IcapOptData *i = s->opt;
++ int valid;
++
++ debug(81, 4) ("icapOptConnectTimeout: fd=%d, service=%s\n", fd, s->uri);
++
++ comm_close(fd);
++ valid = cbdataValid(s);
++ cbdataUnlock(s);
++ if (!valid) {
++ icapOptDataFree(i);
++ s->opt = NULL;
++ return;
++ }
++ /* try again later */
++ icapOptDataFree(i);
++ s->opt = NULL;
++ s->unreachable = 1;
++ debug(81, 3) ("icapOptConnectTimeout: unreachable=1, service=%s\n", s->uri);
++ eventAdd("icapOptStart", icapOptStart, s, Config.icapcfg.check_interval, 1);
++
++}
++
++static void
++icapOptConnectDone(int server_fd, int status, void *data)
++{
++ icap_service *s = data;
++ IcapOptData *i = s->opt;
++ MemBuf request;
++ int valid;
++
++ valid = cbdataValid(s);
++ cbdataUnlock(s);
++ if (!valid) {
++ comm_close(server_fd);
++ icapOptDataFree(i);
++ s->opt = NULL;
++ return;
++ }
++ if (status != COMM_OK) {
++ debug(81, 3) ("icapOptConnectDone: unreachable=1, service=%s\n", s->uri);
++ comm_close(server_fd);
++ icapOptDataFree(i);
++ s->opt = NULL;
++ s->unreachable = 1;
++ eventAdd("icapOptStart", icapOptStart, s, Config.icapcfg.check_interval, 1);
++ return;
++ }
++ debug(81, 3) ("icapOptConnectDone: Connection ok. Sending Options request for %s\n", s->name);
++ memBufDefInit(&request);
++ memBufPrintf(&request, "OPTIONS %s ICAP/1.0\r\n", s->uri);
++ memBufPrintf(&request, "Host: %s\r\n", s->hostname);
++ memBufPrintf(&request, "Connection: close\r\n");
++ memBufPrintf(&request, "User-Agent: ICAP-Client-Squid/1.2\r\n");
++ memBufPrintf(&request, "\r\n");
++ cbdataLock(s);
++ commSetTimeout(server_fd, TIMEOUT, icapOptTimeout, s);
++ comm_write_mbuf(server_fd, request, icapOptWriteComplete, s);
++}
++
++static void
++icapOptWriteComplete(int fd, char *bufnotused, size_t size, int errflag, void *data)
++{
++ icap_service *s = data;
++ IcapOptData *i = s->opt;
++ int valid;
++
++ valid = cbdataValid(s);
++ cbdataUnlock(s);
++ if (!valid) {
++ comm_close(fd);
++ icapOptDataFree(i);
++ s->opt = NULL;
++ return;
++ }
++ debug(81, 5) ("icapOptWriteComplete: FD %d: size %d: errflag %d.\n",
++ fd, size, errflag);
++ if (size > 0) {
++ fd_bytes(fd, size, FD_WRITE);
++ kb_incr(&statCounter.icap.all.kbytes_out, size);
++ }
++ if (errflag) {
++ /* cancel this for now */
++ debug(81, 3) ("icapOptWriteComplete: unreachable=1, service=%s\n", s->uri);
++ icapOptDataFree(i);
++ s->opt = NULL;
++ s->unreachable = 1;
++ eventAdd("icapOptStart", icapOptStart, s, Config.icapcfg.check_interval, 1);
++ comm_close(fd);
++ return;
++ }
++ cbdataLock(s);
++ commSetSelect(fd, COMM_SELECT_READ, icapOptReadReply, s, 0);
++}
++
++static void
++icapOptReadReply(int fd, void *data)
++{
++ icap_service *s = data;
++ IcapOptData *i = s->opt;
++ int size;
++ int len = i->size - i->offset - 1;
++ int valid;
++
++ valid = cbdataValid(s);
++ cbdataUnlock(s);
++ if (!valid) {
++ comm_close(fd);
++ icapOptDataFree(i);
++ s->opt = NULL;
++ return;
++ }
++ if (len == 0) {
++ /* Grow the request memory area to accomodate for a large request */
++ printf("PANIC: not enough memory\n");
++#if 0
++ i->buf = memReallocBuf(i->buf, i->size * 2, &i->size);
++ debug(81, 2) ("icapoptReadReply: growing reply buffer: offset=%ld size=%ld\n",
++ (long) i->offset, (long) i->size);
++ len = i->size - i->offset - 1;
++#endif
++ }
++ size = FD_READ_METHOD(fd, i->buf + i->offset, len);
++ i->offset += size;
++ debug(81, 3) ("icapOptReadReply: Got %d bytes of data\n", size);
++ if (size > 0) {
++ /* do some statistics */
++ fd_bytes(fd, size, FD_READ);
++ kb_incr(&statCounter.icap.all.kbytes_in, size);
++
++ /*
++ * some icap servers seem to ignore the "Connection: close" header. so
++ * after getting the complete option reply we close the connection
++ * ourself.
++ */
++ if ((i->headlen = headersEnd(i->buf, i->offset))) {
++ debug(81, 3) ("icapOptReadReply: EndOfResponse\n");
++ size = 0;
++ }
++ }
++ if (size < 0) {
++ debug(81, 3) ("icapOptReadReply: FD %d: read failure: %s.\n", fd, xstrerror());
++ debug(81, 3) ("icapOptReadReply: unreachable=1, service=%s.\n", s->uri);
++ s->unreachable = 1;
++ icapOptDataFree(i);
++ s->opt = NULL;
++ eventAdd("icapOptStart", icapOptStart, s, Config.icapcfg.check_interval, 1);
++ comm_close(fd);
++ } else if (size == 0) {
++ /* no more data, now we can parse the reply */
++ debug(81, 3) ("icapOptReadReply: FD %d: connection closed\n", fd);
++ i->buf[i->offset] = '\0'; /* for string functions */
++ debug(81, 3) ("icapOptReadReply: unreachable=0, service=%s\n", s->uri);
++
++ if (!icapOptParseReply(s, i)) {
++ debug(81, 3) ("icapOptReadReply: OPTIONS request not successful. scheduling again in %d seconds\n", Config.icapcfg.check_interval);
++ s->unreachable = 1;
++ } else
++ s->unreachable = 0;
++
++ if (s->options_ttl <= 0)
++ s->options_ttl = Config.icapcfg.check_interval;
++ eventAdd("icapOptStart", icapOptStart, s, s->options_ttl, 1);
++
++ icapOptDataFree(i);
++ s->opt = NULL;
++ comm_close(fd);
++ } else {
++ /* data received */
++ /* commSetSelect(fd, Type, handler, client_data, timeout) */
++ cbdataLock(s);
++ commSetSelect(fd, COMM_SELECT_READ, icapOptReadReply, data, 0);
++ }
++}
++
++static int
++icapIsolateLine(const char **parse_start, const char **blk_start, const char **blk_end)
++{
++ int slen = strcspn(*parse_start, "\r\n");
++
++ if (!(*parse_start)[slen]) /* no crlf */
++ return 0;
++
++ if (slen == 0) /* empty line */
++ return 0;
++
++ *blk_start = *parse_start;
++ *blk_end = *blk_start + slen;
++
++ /* set it to the beginning of next line */
++ *parse_start = *blk_end;
++ while (**parse_start == '\r') /* CR */
++ (*parse_start)++;
++ if (**parse_start == '\n') /* LF */
++ (*parse_start)++;
++ return 1;
++}
++
++/* process a single header entry between blk_start and blk_end */
++static void
++icapOptParseEntry(icap_service * s, const char *blk_start, const char *blk_end)
++{
++ const char *name_end = strchr(blk_start, ':');
++ const int name_len = name_end ? name_end - blk_start : 0;
++ const char *value_start = blk_start + name_len + 1; /* skip ':' */
++ int value_len;
++ int new;
++
++ if (!name_len || name_end > blk_end) {
++ debug(81, 5) ("icapOptParseEntry: strange header. skipping\n");
++ return;
++ }
++ if (name_len > 65536) {
++ debug(81, 5) ("icapOptParseEntry: unusual long header item. skipping.\n");
++ return;
++ }
++ while (xisspace(*value_start) && value_start < blk_end) {
++ value_start++;
++ }
++ if (value_start >= blk_end) {
++ debug(81, 5) ("icapOptParseEntry: no value found\n");
++ return;
++ }
++ value_len = blk_end - value_start;
++
++
++ /* extract information */
++ if (!strncasecmp("Allow", blk_start, name_len)) {
++ debug(81, 5) ("icapOptParseEntry: found Allow\n");
++ if (!strncmp("204", value_start, 3)) {
++ s->flags.allow_204 = 1;
++ } else {
++ debug(81, 3) ("icapOptParseEntry: Allow value unknown");
++ }
++ } else if (!strncasecmp("Connection", blk_start, name_len)) {
++ debug(81, 5) ("icapOptParseEntry: found Connection\n");
++ } else if (!strncasecmp("Encapsulated", blk_start, name_len)) {
++ debug(81, 5) ("icapOptParseEntry: found Encapsulated\n");
++ } else if (!strncasecmp("ISTAG", blk_start, name_len)) {
++ debug(81, 5) ("icapOptParseEntry: found ISTAG\n");
++ stringClean(&s->istag);
++ stringLimitInit(&s->istag, value_start, value_len);
++ } else if (!strncasecmp("Max-Connections", blk_start, name_len)) {
++ debug(81, 5) ("icapOptParseEntry: found Max-Connections\n");
++ errno = 0;
++ new = strtol(value_start, NULL, 10);
++ if (errno) {
++ debug(81, 5) ("icapOptParseEntry: Max-Connections: could not parse value\n");
++ } else {
++ debug(81, 5) ("icapOptParseEntry: Max-Connections: new value=%d\n", new);
++ s->max_connections = new;
++ }
++ } else if (!strncasecmp("Methods", blk_start, name_len)) {
++ debug(81, 5) ("icapOptParseEntry: found Methods\n");
++ } else if (!strncasecmp("Options-TTL", blk_start, name_len)) {
++ debug(81, 5) ("icapOptParseEntry: found Options-TTL\n");
++ errno = 0;
++ new = strtol(value_start, NULL, 10);
++ if (errno) {
++ debug(81, 5) ("icapOptParseEntry: Options-TTL: could not parse value\n");
++ } else {
++ debug(81, 5) ("icapOptParseEntry: Options-TTL: new value=%d\n", new);
++ s->options_ttl = new;
++ }
++ } else if (!strncasecmp("Preview", blk_start, name_len)) {
++ debug(81, 5) ("icapOptParseEntry: found Preview\n");
++ errno = 0;
++ new = strtol(value_start, NULL, 10);
++ if (errno) {
++ debug(81, 5) ("icapOptParseEntry: Preview: could not parse value\n");
++ } else {
++ debug(81, 5) ("icapOptParseEntry: Preview: new value=%d\n", new);
++ s->preview = new;
++ }
++ } else if (!strncasecmp("Service", blk_start, name_len)) {
++ debug(81, 5) ("icapOptParseEntry: found Service\n");
++ } else if (!strncasecmp("Service-ID", blk_start, name_len)) {
++ debug(81, 5) ("icapOptParseEntry: found Service-ID\n");
++ } else if (!strncasecmp("Transfer-Preview", blk_start, name_len)) {
++ debug(81, 5) ("icapOptParseEntry: found Transfer-Preview\n");
++ stringClean(&s->transfer_preview);
++ stringLimitInit(&s->transfer_preview, value_start, value_len);
++ } else if (!strncasecmp("Transfer-Ignore", blk_start, name_len)) {
++ debug(81, 5) ("icapOptParseEntry: found Transfer-Ignore\n");
++ stringClean(&s->transfer_ignore);
++ stringLimitInit(&s->transfer_ignore, value_start, value_len);
++ } else if (!strncasecmp("Transfer-Complete", blk_start, name_len)) {
++ debug(81, 5) ("icapOptParseEntry: found Transfer-Complete\n");
++ stringClean(&s->transfer_complete);
++ stringLimitInit(&s->transfer_complete, value_start, value_len);
++ } else if (!strncasecmp("X-Include", blk_start, name_len)) {
++ debug(81, 5) ("icapOptParseEntry: found X-Include\n");
++ if (strstr(value_start, "X-Client-IP")) {
++ debug(81, 5) ("icapOptParseEntry: X-Include: found X-Client-IP\n");
++ s->flags.need_x_client_ip = 1;
++ }
++ if (strstr(value_start, "X-Server-IP")) {
++ debug(81, 5) ("icapOptParseEntry: X-Include: found X-Server-IP\n");
++ s->flags.need_x_server_ip = 1;
++ }
++ if (strstr(value_start, "X-Authenticated-User")) {
++ debug(81, 5) ("icapOptParseEntry: X-Include: found X-Authenticated-User\n");
++ s->flags.need_x_authenticated_user = 1;
++ }
++ } else {
++ debug(81, 5) ("icapOptParseEntry: unknown options header\n");
++ }
++}
++
++/* parse OPTIONS reply */
++static int
++icapOptParseReply(icap_service * s, IcapOptData * i)
++{
++ int version_major, version_minor;
++ const char *str_status;
++ int status;
++ const char *buf = i->buf;
++ const char *parse_start;
++ const char *head_end;
++ const char *blk_start;
++ const char *blk_end;
++
++ if ((status =
++ icapParseStatusLine(i->buf, i->offset,
++ &version_major, &version_minor, &str_status)) < 0) {
++ debug(81, 2) ("icapOptParseReply: bad status line <%s>\n", i->buf);
++ return 0;
++ }
++ debug(81, 3) ("icapOptParseReply: got reply: <ICAP/%d.%d %d %s>\n", version_major, version_minor, status, str_status);
++
++ if (status != 200) {
++ debug(81, 3) ("icapOptParseReply: status = %d != 200\n", status);
++ return 0;
++ }
++ parse_start = buf;
++ if (i->headlen == 0)
++ i->headlen = headersEnd(parse_start, s->opt->offset);
++
++ if (!i->headlen) {
++ debug(81, 2) ("icapOptParseReply: end of headers could not be found\n");
++ return 0;
++ }
++ head_end = parse_start + i->headlen - 1;
++ while (*(head_end - 1) == '\r')
++ head_end--;
++ assert(*(head_end - 1) == '\n');
++ if (*head_end != '\r' && *head_end != '\n')
++ return 0; /* failure */
++
++ /* skip status line */
++ if (!icapIsolateLine(&parse_start, &blk_start, &blk_end)) {
++ debug(81, 3) ("icapOptParseReply: failure in isolating status line\n");
++ return 0;
++
++ }
++ /* now we might start real parsing */
++ while (icapIsolateLine(&parse_start, &blk_start, &blk_end)) {
++ if (blk_end > head_end || blk_start > head_end || blk_start >= blk_end) {
++ debug(81, 3) ("icapOptParseReply: header limit exceeded. finished.\n");
++ break;
++ }
++ icapOptParseEntry(s, blk_start, blk_end);
++ }
++ return 1;
++}
++
++static void
++icapOptDataInit(IcapOptData * i)
++{
++ i->buf = memAllocBuf(HTTP_REPLY_BUF_SZ, &i->size);
++ i->offset = 0;
++ i->headlen = 0;
++}
++
++static void
++icapOptDataFree(IcapOptData * i)
++{
++ if (i) {
++ memFreeBuf(i->size, i->buf);
++ memFree(i, MEM_ICAP_OPT_DATA);
++ }
++}
+Index: src/icap_reqmod.c
+===================================================================
+RCS file: src/icap_reqmod.c
+diff -N src/icap_reqmod.c
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ src/icap_reqmod.c 13 Jun 2006 17:14:53 -0000 1.1.14.6
+@@ -0,0 +1,992 @@
++
++/*
++ * $Id$
++ *
++ * DEBUG: section 81 Internet Content Adaptation Protocol (ICAP) Client
++ * AUTHOR: Geetha Manjunath, Hewlett Packard Company
++ *
++ * 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"
++
++#define ICAP_PROXY_KEEP_ALIVE 0
++
++/*
++ * These once-static functions are required to be global for ICAP
++ */
++
++PF clientReadRequest;
++PF connStateFree;
++int clientReadDefer(int fd, void *data);
++int clientCheckContentLength(request_t * r);
++void clientProcessRequest(clientHttpRequest *);
++int clientCachable(clientHttpRequest *);
++int clientHierarchical(clientHttpRequest *);
++void clientReadBody(request_t * request, char *buf, size_t size,
++ CBCB * callback, void *cbdata);
++static void icapReqModPassHttpBody(IcapStateData * icap, char *buf, size_t size,
++ CBCB * callback, void *cbdata);
++
++static PF icapReqModReadHttpHdrs;
++static PF icapReqModReadHttpBody;
++static CWCB icapReqModSendBodyChunk;
++static CBCB icapReqModBodyHandler;
++static BODY_HANDLER icapReqModBodyReader;
++static STRCB icapReqModMemBufAppend;
++
++#define EXPECTED_ICAP_HEADER_LEN 256
++static const char *crlf = "\r\n";
++
++/*
++ * icapExpectedHttpReqHdrSize
++ *
++ * calculate the size of the HTTP headers that we expect
++ * to read from the ICAP server.
++ */
++static int
++icapExpectedHttpReqHdrSize(IcapStateData * icap)
++{
++ if (icap->enc.req_body > -1 && icap->enc.req_hdr > -1)
++ return (icap->enc.req_body - icap->enc.req_hdr);
++ if (icap->enc.null_body > -1)
++ return icap->enc.null_body;
++ fatal("icapExpectedHttpReqHdrSize: unexpected case");
++ return 0;
++}
++
++/*
++ * icapReqModCreateClientState
++ *
++ * Creates fake client_side data structures so we can use
++ * that module to read/parse the HTTP request that we read
++ * from the ICAP server.
++ */
++static clientHttpRequest *
++icapReqModCreateClientState(IcapStateData * icap, request_t * request)
++{
++ clientHttpRequest *http;
++ if (!cbdataValid(icap->reqmod.client_cookie)) {
++ debug(81, 3) ("Whups, client cookie invalid\n");
++ icap->reqmod.client_fd = -1;
++ return NULL;
++ }
++ http = cbdataAlloc(clientHttpRequest);
++ /*
++ * use our own urlCanonicalClean here, because urlCanonicalClean
++ * may strip everything after a question-mark. As http->uri
++ * is used when doing a request to a parent proxy, we need the full
++ * url here.
++ */
++ http->uri = xstrdup(urlCanonical(icap->request));
++ http->log_uri = xstrndup(http->uri, MAX_URL);
++ http->range_iter.boundary = StringNull;
++ http->request = requestLink(request ? request : icap->request);
++ http->flags.did_icap_reqmod = 1;
++ http->start = icap->reqmod.start;
++ if (request)
++ http->http_ver = request->http_ver;
++#if ICAP_PROXY_KEEP_ALIVE
++ /*
++ * Here it is possible becouse we are using as client_cookie the original http->conn
++ * if we will keep this code we must declare an icap->conn field........
++ * Will work if pipeline_prefetch is not enabled
++ * We are using a dummy ConnStateData structure, just to free
++ * old clientHttpRequest :-(
++ * OK,all this code is a hack and possibly must not exists in cvs ......
++ */
++
++ http->conn = icap->reqmod.client_cookie;
++ assert(http->conn->chr->next == NULL);
++ {
++ ConnStateData *dummyconn;
++ dummyconn = cbdataAlloc(ConnStateData);
++ dummyconn->fd = icap->reqmod.client_fd;
++ dummyconn->pinning.fd = -1;
++ dummyconn->chr = http->conn->chr;
++ dummyconn->chr->conn = dummyconn;
++ comm_add_close_handler(dummyconn->fd, connStateFree, dummyconn);
++ }
++ http->conn->chr = http;
++#else
++ http->conn = cbdataAlloc(ConnStateData);
++ http->conn->fd = icap->reqmod.client_fd;
++ http->conn->pinning.fd = -1;
++ http->conn->in.size = 0;
++ http->conn->in.buf = NULL;
++ http->conn->log_addr = icap->reqmod.log_addr;
++ http->conn->chr = http;
++ comm_add_close_handler(http->conn->fd, connStateFree, http->conn);
++#endif
++ http->icap_reqmod = NULL;
++ return http;
++}
++
++/*
++ * icapReqModInterpretHttpRequest
++ *
++ * Interpret an HTTP request that we read from the ICAP server.
++ * Create some "fake" clientHttpRequest and ConnStateData structures
++ * so we can pass this new request off to the routines in
++ * client_side.c.
++ */
++static void
++icapReqModInterpretHttpRequest(IcapStateData * icap, request_t * request)
++{
++ clientHttpRequest *http = icapReqModCreateClientState(icap, request);
++ if (NULL == http)
++ return;
++ /*
++ * bits from clientReadRequest
++ */
++ request->content_length = httpHeaderGetSize(&request->header,
++ HDR_CONTENT_LENGTH);
++ if (!urlCheckRequest(request) ||
++ httpHeaderHas(&request->header, HDR_TRANSFER_ENCODING)) {
++ ErrorState *err;
++ err = errorCon(ERR_UNSUP_REQ, HTTP_NOT_IMPLEMENTED);
++ err->request = requestLink(request);
++ request->flags.proxy_keepalive = 0;
++ http->entry =
++ clientCreateStoreEntry(http, request->method, null_request_flags);
++ errorAppendEntry(http->entry, err);
++ return;
++ }
++ if (!clientCheckContentLength(request)) {
++ ErrorState *err;
++ err = errorCon(ERR_INVALID_REQ, HTTP_LENGTH_REQUIRED);
++ err->request = requestLink(request);
++ http->entry =
++ clientCreateStoreEntry(http, request->method, null_request_flags);
++ errorAppendEntry(http->entry, err);
++ return;
++ }
++ /* Do we expect a request-body? */
++ if (request->content_length > 0) {
++ debug(81, 5) ("handing request bodies in ICAP REQMOD\n");
++ if (request->body_reader_data)
++ cbdataUnlock(request->body_reader_data);
++ request->body_reader = icapReqModBodyReader;
++ request->body_reader_data = icap; /* XXX cbdataLock? */
++ cbdataLock(icap); /*Yes sure ..... */
++ memBufDefInit(&icap->reqmod.http_entity.buf);
++ }
++ if (clientCachable(http))
++ request->flags.cachable = 1;
++ if (clientHierarchical(http))
++ request->flags.hierarchical = 1;
++ clientProcessRequest(http);
++}
++
++/*
++ * icapReqModParseHttpError
++ *
++ * Handle an error when parsing the new HTTP request we read
++ * from the ICAP server.
++ */
++static void
++icapReqModParseHttpError(IcapStateData * icap, const char *reason)
++{
++ debug(81, 1) ("icapReqModParseHttpError: %s\n", reason);
++}
++
++/*
++ * icapEntryError
++ *
++ * A wrapper for errorCon() and errorAppendEntry().
++ */
++static void
++icapEntryError(IcapStateData * icap, err_type et, http_status hs, int xerrno)
++{
++ ErrorState *err;
++ clientHttpRequest *http = icapReqModCreateClientState(icap, NULL);
++ if (NULL == http)
++ return;
++ http->entry = clientCreateStoreEntry(http,
++ icap->request->method, null_request_flags);
++ err = errorCon(et, hs);
++ err->xerrno = xerrno;
++ err->request = requestLink(icap->request);
++ errorAppendEntry(http->entry, err);
++}
++
++/*
++ * icapReqModParseHttpRequest
++ *
++ * Parse the HTTP request that we read from the ICAP server.
++ * Creates and fills in the request_t structure.
++ */
++static void
++icapReqModParseHttpRequest(IcapStateData * icap)
++{
++ char *mstr;
++ char *uri;
++ char *inbuf;
++ char *t;
++ char *token;
++ char *headers;
++ method_t method;
++ request_t *request;
++ http_version_t http_ver;
++ int reqlen = icap->reqmod.hdr_buf.size;
++ int hdrlen;
++
++ /*
++ * Lazy, make a copy of the buf so I can chop it up with strtok()
++ */
++ inbuf = xcalloc(reqlen + 1, 1);
++ memcpy(inbuf, icap->reqmod.hdr_buf.buf, reqlen);
++
++ if ((mstr = strtok(inbuf, "\t ")) == NULL) {
++ debug(81, 1) ("icapReqModParseHttpRequest: Can't get request method\n");
++ icapReqModParseHttpError(icap, "error:invalid-request-method");
++ xfree(inbuf);
++ return;
++ }
++ method = urlParseMethod(mstr);
++ if (method == METHOD_NONE) {
++ debug(81, 1) ("icapReqModParseHttpRequest: Unsupported method '%s'\n",
++ mstr);
++ icapReqModParseHttpError(icap, "error:unsupported-request-method");
++ xfree(inbuf);
++ return;
++ }
++ /* look for URL+HTTP/x.x */
++ if ((uri = strtok(NULL, "\n")) == NULL) {
++ debug(81, 1) ("icapReqModParseHttpRequest: Missing URI\n");
++ icapReqModParseHttpError(icap, "error:missing-url");
++ xfree(inbuf);
++ return;
++ }
++ while (xisspace(*uri))
++ uri++;
++ t = uri + strlen(uri);
++ assert(*t == '\0');
++ token = NULL;
++ while (t > uri) {
++ t--;
++ if (xisspace(*t) && !strncmp(t + 1, "HTTP/", 5)) {
++ token = t + 1;
++ break;
++ }
++ }
++ while (t > uri && xisspace(*t))
++ *(t--) = '\0';
++ debug(81, 5) ("icapReqModParseHttpRequest: URI is '%s'\n", uri);
++ if (token == NULL) {
++ debug(81, 3) ("icapReqModParseHttpRequest: Missing HTTP identifier\n");
++ icapReqModParseHttpError(icap, "error:missing-http-ident");
++ xfree(inbuf);
++ return;
++ }
++ if (sscanf(token + 5, "%d.%d", &http_ver.major, &http_ver.minor) != 2) {
++ debug(81, 3) ("icapReqModParseHttpRequest: Invalid HTTP identifier.\n");
++ icapReqModParseHttpError(icap, "error:invalid-http-ident");
++ xfree(inbuf);
++ return;
++ }
++ debug(81, 6) ("icapReqModParseHttpRequest: Client HTTP version %d.%d.\n",
++ http_ver.major, http_ver.minor);
++
++ headers = strtok(NULL, null_string);
++ hdrlen = inbuf + reqlen - headers;
++
++ if ((request = urlParse(method, uri)) == NULL) {
++ debug(81, 3) ("Invalid URL: %s at %s:%d\n", uri, __FILE__, __LINE__);
++ icapEntryError(icap, ERR_INVALID_URL, HTTP_BAD_REQUEST, 0);
++ xfree(inbuf);
++ return;
++ }
++ /* compile headers */
++ if (!httpHeaderParse(&request->header, headers, headers + hdrlen)) {
++ debug(81, 3) ("Failed to parse HTTP headers for: %s at %s:%d",
++ uri, __FILE__, __LINE__);
++ icapEntryError(icap, ERR_INVALID_REQ, HTTP_BAD_REQUEST, 0);
++ xfree(inbuf);
++ return;
++ }
++ debug(81,
++ 3)
++ ("icapReqModParseHttpRequest: successfully parsed the HTTP request\n");
++ request->http_ver = http_ver;
++ request->client_addr = icap->request->client_addr;
++ request->client_port = icap->request->client_port;
++ request->my_addr = icap->request->my_addr;
++ request->my_port = icap->request->my_port;
++ request->class = icap->request->class;
++ if (icap->request->auth_user_request) {
++ /* Copy authentification info in new request */
++ request->auth_user_request = icap->request->auth_user_request;
++ authenticateAuthUserRequestLock(request->auth_user_request);
++ }
++ request->content_length = httpHeaderGetSize(&request->header,
++ HDR_CONTENT_LENGTH);
++ if (strBuf(icap->request->extacl_log))
++ request->extacl_log = stringDup(&icap->request->extacl_log);
++ if (icap->request->extacl_user)
++ request->extacl_user = xstrdup(icap->request->extacl_user);
++ if (icap->request->extacl_passwd)
++ request->extacl_passwd = xstrdup(icap->request->extacl_passwd);
++#if ICAP_PROXY_KEEP_ALIVE
++ /*
++ * Copy the proxy_keepalive flag from the original request
++ */
++ request->flags.proxy_keepalive = icap->request->flags.proxy_keepalive;
++ /*
++ * If proxy_keepalive was set for the original request, make
++ * sure that the adapated request also has the necessary headers
++ * for keepalive
++ */
++ if (request->flags.proxy_keepalive) {
++ if (!httpMsgIsPersistent(http_ver, &request->header))
++ request->flags.proxy_keepalive = 0;
++ }
++#endif
++ icapReqModInterpretHttpRequest(icap, request);
++ xfree(inbuf);
++}
++
++/*
++ * icapReqModHandoffRespMod
++ *
++ * Handles the case where a REQMOD request results in an HTTP REPLY
++ * (instead of an ICAP REPLY that contains a new HTTP REQUEST). We
++ * prepare the IcapStateData for passing off to the icap_reqmod
++ * code, where we have functions for reading HTTP replies in ICAP
++ * messages.
++ */
++static void
++icapReqModHandoffRespMod(IcapStateData * icap)
++{
++ extern PF icapReadReply;
++ clientHttpRequest *http = icapReqModCreateClientState(icap, NULL);
++ if (NULL == http)
++ return;
++ assert(icap->request);
++
++ http->entry = clientCreateStoreEntry(http,
++ icap->request->method, icap->request->flags);
++ icap->respmod.entry = http->entry;
++ storeLockObject(icap->respmod.entry);
++
++ /* icap->http_flags = ? */
++ memBufDefInit(&icap->respmod.buffer);
++ memBufDefInit(&icap->chunk_buf);
++ assert(icap->current_service);
++ icapReadReply(icap->icap_fd, icap);
++}
++
++/*
++ * icapReqModKeepAliveOrClose
++ *
++ * Called when we are done reading from the ICAP server.
++ * Either close the connection or keep it open for a future
++ * transaction.
++ */
++static void
++icapReqModKeepAliveOrClose(IcapStateData * icap)
++{
++ int fd = icap->icap_fd;
++ debug(81, 3) ("%s:%d FD %d\n", __FILE__, __LINE__, fd);
++ if (fd < 0)
++ return;
++ if (!icap->flags.keep_alive) {
++ debug(81, 3) ("%s:%d keep_alive not set, closing\n", __FILE__,
++ __LINE__);
++ comm_close(fd);
++ return;
++ }
++ if (icap->request->content_length < 0) {
++ /* no message body */
++ debug(81, 3) ("%s:%d no message body\n", __FILE__, __LINE__);
++ if (1 != icap->reqmod.hdr_state) {
++ /* didn't get to end of HTTP headers */
++ debug(81, 3) ("%s:%d didnt find end of headers, closing\n",
++ __FILE__, __LINE__);
++ comm_close(fd);
++ return;
++ }
++ } else if (icap->reqmod.http_entity.bytes_read !=
++ icap->request->content_length) {
++ debug(81, 3) ("%s:%d bytes_read (%" PRINTF_OFF_T ") != content_length (%" PRINTF_OFF_T ")\n",
++ __FILE__, __LINE__, icap->reqmod.http_entity.bytes_read,
++ icap->request->content_length);
++ /* an error */
++ comm_close(fd);
++ return;
++ }
++ debug(81, 3) ("%s:%d looks good, keeping alive\n", __FILE__, __LINE__);
++ commSetDefer(fd, NULL, NULL);
++ commSetTimeout(fd, -1, NULL, NULL);
++ commSetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0);
++ comm_remove_close_handler(fd, icapStateFree, icap);
++ pconnPush(fd, icap->current_service->hostname, icap->current_service->port, NULL, NULL, 0);
++ icap->icap_fd = -1;
++ icapStateFree(-1, icap);
++}
++
++/*
++ * icapReqModReadHttpHdrs
++ *
++ * Read the HTTP reply from the ICAP server. Uses the values
++ * from the ICAP Encapsulation header to know how many bytes
++ * to read.
++ */
++static void
++icapReqModReadHttpHdrs(int fd, void *data)
++{
++ IcapStateData *icap = data;
++ LOCAL_ARRAY(char, tmpbuf, SQUID_TCP_SO_RCVBUF);
++ int rl;
++ debug(81, 3) ("icapReqModReadHttpHdrs:\n");
++ assert(fd == icap->icap_fd);
++ assert(icap->enc.req_hdr == 0);
++ if (0 == icap->reqmod.hdr_state) {
++ int expect = icapExpectedHttpReqHdrSize(icap);
++ int so_far = icap->http_header_bytes_read_so_far;
++ int needed = expect - so_far;
++ debug(81, 3) ("expect=%d\n", expect);
++ debug(81, 3) ("so_far=%d\n", so_far);
++ debug(81, 3) ("needed=%d\n", needed);
++ assert(needed >= 0);
++ if (0 == expect) {
++ fatalf("unexpected condition in %s:%d", __FILE__, __LINE__);
++ }
++ rl = FD_READ_METHOD(fd, tmpbuf, needed);
++ debug(81, 3) ("icapReqModReadHttpHdrs: read %d bytes\n", rl);
++ if (rl < 0) {
++ fatalf("need to handle read error at %s:%d", __FILE__, __LINE__);
++ }
++ fd_bytes(fd, rl, FD_READ);
++ kb_incr(&statCounter.icap.all.kbytes_in, rl);
++ memBufAppend(&icap->reqmod.hdr_buf, tmpbuf, rl);
++ icap->http_header_bytes_read_so_far += rl;
++ if (rl != needed) {
++ /* still more header data to read */
++ commSetSelect(fd, COMM_SELECT_READ, icapReqModReadHttpHdrs, icap,
++ 0);
++ return;
++ }
++ icap->reqmod.hdr_state = 1;
++ }
++ assert(1 == icap->reqmod.hdr_state);
++ debug(81, 3) ("icapReqModReadHttpHdrs: read the entire request headers\n");
++ icapReqModParseHttpRequest(icap);
++ if (-1 == icap->reqmod.client_fd) {
++ /* we detected that the original client_side went away */
++ icapReqModKeepAliveOrClose(icap);
++ } else if (icap->enc.req_body > -1) {
++ icap->chunk_size = 0;
++ memBufDefInit(&icap->chunk_buf);
++ commSetSelect(fd, COMM_SELECT_READ, icapReqModReadHttpBody, icap, 0);
++ } else {
++ icapReqModKeepAliveOrClose(icap);
++ }
++}
++
++
++/*
++ * icapReqModReadIcapPart
++ *
++ * Read the ICAP reply header.
++ */
++static void
++icapReqModReadIcapPart(int fd, void *data)
++{
++ IcapStateData *icap = data;
++ int version_major, version_minor;
++ const char *str_status;
++ int x;
++ const char *start;
++ const char *end;
++ int status;
++ int isIcap = 0;
++ int directResponse = 0;
++
++ debug(81, 5) ("icapReqModReadIcapPart: FD %d httpState = %p\n", fd, data);
++ statCounter.syscalls.sock.reads++;
++
++ x = icapReadHeader(fd, icap, &isIcap);
++ if (x < 0) {
++ /* Did not find a proper ICAP response */
++ debug(81, 3) ("ICAP : Error path!\n");
++ icapEntryError(icap, ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR,
++ errno);
++ comm_close(fd);
++ return;
++ }
++ if (x == 0) {
++ /*
++ * Waiting for more headers. Schedule new read hander, but
++ * don't reset timeout.
++ */
++ commSetSelect(fd, COMM_SELECT_READ, icapReqModReadIcapPart, icap, 0);
++ return;
++ }
++ /*
++ * Parse the ICAP header
++ */
++ assert(icap->icap_hdr.size);
++ debug(81, 3) ("Read icap header : <%s>\n", icap->icap_hdr.buf);
++ if ((status =
++ icapParseStatusLine(icap->icap_hdr.buf, icap->icap_hdr.size,
++ &version_major, &version_minor, &str_status)) < 0) {
++ debug(81, 1) ("BAD ICAP status line <%s>\n", icap->icap_hdr.buf);
++ /* is this correct in case of ICAP protocol error? */
++ icapEntryError(icap, ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR,
++ errno);
++ comm_close(fd);
++ return;
++ };
++ if (200 != status && 201 != status) {
++ debug(81, 1) ("Unsupported status '%d' from ICAP server\n", status);
++ icapEntryError(icap, ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR,
++ errno);
++ comm_close(fd);
++ return;
++ }
++ icapSetKeepAlive(icap, icap->icap_hdr.buf);
++ if (icapFindHeader(icap->icap_hdr.buf, "Encapsulated:", &start, &end)) {
++ icapParseEncapsulated(icap, start, end);
++ } else {
++ debug(81,
++ 1)
++ ("WARNING: icapReqModReadIcapPart() did not find 'Encapsulated' header\n");
++ }
++ if (icap->enc.res_hdr > -1)
++ directResponse = 1;
++ else if (icap->enc.res_body > -1)
++ directResponse = 1;
++ else
++ directResponse = 0;
++ debug(81, 3) ("icapReqModReadIcapPart: directResponse=%d\n",
++ directResponse);
++
++ /* Check whether it is a direct reply - if so over to http part */
++ if (directResponse) {
++ debug(81,
++ 3)
++ ("icapReqModReadIcapPart: FD %d, processing HTTP response for REQMOD!\n",
++ fd);
++ /* got the reply, no need to come here again */
++ icap->flags.wait_for_reply = 0;
++ icap->flags.got_reply = 1;
++ icapReqModHandoffRespMod(icap);
++ return;
++ }
++ memBufDefInit(&icap->reqmod.hdr_buf);
++ commSetSelect(fd, COMM_SELECT_READ, icapReqModReadHttpHdrs, icap, 0);
++ return;
++}
++
++/*
++ * icapSendReqModDone
++ *
++ * Called after we've sent the ICAP request. Checks for errors
++ * and installs the handler functions for the next step.
++ */
++static void
++icapSendReqModDone(int fd, char *bufnotused, size_t size, int errflag,
++ void *data)
++{
++ IcapStateData *icap = data;
++
++ debug(81, 5) ("icapSendReqModDone: FD %d: size %d: errflag %d.\n",
++ fd, size, errflag);
++ if (size > 0) {
++ fd_bytes(fd, size, FD_WRITE);
++ kb_incr(&statCounter.icap.all.kbytes_out, size);
++ }
++ if (errflag == COMM_ERR_CLOSING)
++ return;
++ if (errflag) {
++ debug(81, 3) ("icapSendReqModDone: unreachable=1, service=%s\n",
++ icap->current_service->uri);
++ icapOptSetUnreachable(icap->current_service);
++ icapEntryError(icap, ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR,
++ errno);
++ comm_close(fd);
++ return;
++ }
++ /* Schedule read reply. */
++ commSetSelect(fd, COMM_SELECT_READ, icapReqModReadIcapPart, icap, 0);
++ /*
++ * Set the read timeout here because it hasn't been set yet.
++ * We only set the read timeout after the request has been
++ * fully written to the server-side. If we start the timeout
++ * after connection establishment, then we are likely to hit
++ * the timeout for POST/PUT requests that have very large
++ * request bodies.
++ */
++ commSetTimeout(fd, Config.Timeout.read, icapConnectTimeout, icap);
++}
++
++
++/*
++ * icapSendReqMod
++ *
++ * Send the ICAP request, including HTTP request, to the ICAP server
++ * after connection has been established.
++ */
++static void
++icapSendReqMod(int fd, int status, void *data)
++{
++ MemBuf mb;
++ MemBuf mb_hdr;
++ Packer p;
++ IcapStateData *icap = data;
++ char *client_addr;
++ int icap_fd = icap->icap_fd;
++ icap_service *service;
++ CWCB *theCallback;
++
++ debug(81, 5) ("icapSendReqMod FD %d, status %d\n", fd, status);
++ icap->flags.connect_pending = 0;
++
++ if (COMM_OK != status) {
++ debug(81, 1) ("Could not connect to ICAP server %s:%d: %s\n",
++ icap->current_service->hostname,
++ icap->current_service->port, xstrerror());
++ debug(81, 3) ("icapSendReqMod: unreachable=1, service=%s\n",
++ icap->current_service->uri);
++ icapOptSetUnreachable(icap->current_service);
++ icapEntryError(icap, ERR_ICAP_FAILURE, HTTP_SERVICE_UNAVAILABLE, errno);
++ comm_close(fd);
++ return;
++ }
++ fd_table[fd].pconn.uses++;
++ fd_table[fd].pconn.type = 2;
++ if (icap->request->content_length > 0)
++ theCallback = icapReqModSendBodyChunk;
++ else
++ theCallback = icapSendReqModDone;
++
++ memBufDefInit(&mb);
++ memBufDefInit(&mb_hdr);
++ memBufPrintf(&mb_hdr, "%s %s HTTP/%d.%d\r\n",
++ RequestMethodStr[icap->request->method],
++ icap->reqmod.uri,
++ icap->request->http_ver.major, icap->request->http_ver.minor);
++ packerToMemInit(&p, &mb_hdr);
++ httpHeaderPackInto(&icap->request->header, &p);
++ packerClean(&p);
++ memBufAppend(&mb_hdr, crlf, 2);
++ service = icap->current_service;
++ assert(service);
++ client_addr = inet_ntoa(icap->request->client_addr);
++
++ memBufPrintf(&mb, "REQMOD %s ICAP/1.0\r\n", service->uri);
++ memBufPrintf(&mb, "Encapsulated: req-hdr=0");
++ /* TODO: Change the offset using 'request' if needed */
++ if (icap->request->content_length > 0)
++ memBufPrintf(&mb, ", req-body=%d", mb_hdr.size);
++ else
++ memBufPrintf(&mb, ", null-body=%d", mb_hdr.size);
++ memBufAppend(&mb, crlf, 2);
++
++ if (service->flags.need_x_client_ip && Config.icapcfg.send_client_ip)
++ memBufPrintf(&mb, "X-Client-IP: %s\r\n", client_addr);
++
++ if (service->flags.need_x_server_ip && Config.icapcfg.send_server_ip)
++ icapAddOriginIP(&mb, icap->request->host);
++
++ if ((service->flags.need_x_authenticated_user
++ && Config.icapcfg.send_auth_user)
++ && (icap->request->auth_user_request != NULL))
++ icapAddAuthUserHeader(&mb, icap->request->auth_user_request);
++ if (service->keep_alive) {
++ icap->flags.keep_alive = 1;
++ } else {
++ icap->flags.keep_alive = 0;
++ memBufAppend(&mb, "Connection: close\r\n", 19);
++ }
++ memBufAppend(&mb, crlf, 2);
++ memBufAppend(&mb, mb_hdr.buf, mb_hdr.size);
++ memBufClean(&mb_hdr);
++
++ debug(81, 5) ("icapSendReqMod: FD %d writing {%s}\n", icap->icap_fd,
++ mb.buf);
++ comm_write_mbuf(icap_fd, mb, theCallback, icap);
++}
++
++/*
++ * icapReqModStart
++ *
++ * Initiate an ICAP REQMOD transaction. Create and fill in IcapStateData
++ * structure and request a TCP connection to the server.
++ */
++IcapStateData *
++icapReqModStart(icap_service * service, const char *uri, request_t * request,
++ int fd, struct timeval start, struct in_addr log_addr, void *cookie)
++{
++ IcapStateData *icap = NULL;
++
++ debug(81, 3) ("icapReqModStart: type=%d\n", (int) service->type);
++
++ switch (service->type) {
++ case ICAP_SERVICE_REQMOD_PRECACHE:
++ break;
++ default:
++ fatalf("icapReqModStart: unsupported service type '%s'\n",
++ icap_service_type_str[service->type]);
++ break;
++ }
++
++ if (service->unreachable) {
++ if (service->bypass) {
++ debug(81,
++ 5) ("icapReqModStart: BYPASS because service unreachable: %s\n",
++ service->uri);
++ return NULL;
++ } else {
++ debug(81,
++ 5) ("icapReqModStart: ERROR because service unreachable: %s\n",
++ service->uri);
++ return (IcapStateData *) - 1;
++ }
++ }
++ icap = icapAllocate();
++ if (!icap) {
++ debug(81, 3) ("icapReqModStart: icapAllocate() failed\n");
++ return NULL;
++ }
++ icap->current_service = service;
++ icap->preview_size = service->preview;
++ icap->reqmod.uri = uri; /* XXX should be xstrdup? */
++ icap->reqmod.start = start;
++ icap->reqmod.log_addr = log_addr;
++ icap->request = requestLink(request);
++ icap->reqmod.hdr_state = 0;
++ icap->reqmod.client_fd = fd;
++ icap->reqmod.client_cookie = cookie;
++ cbdataLock(icap->reqmod.client_cookie);
++
++ if (!icapConnect(icap, icapSendReqMod))
++ return NULL;
++
++ statCounter.icap.all.requests++;
++ debug(81, 3) ("icapReqModStart: returning %p\n", icap);
++ return icap;
++}
++
++/*
++ * icapReqModSendBodyChunk
++ *
++ * A "comm_write" callback. This is called after comm_write() does
++ * its job to let us know how things went. If there are no errors,
++ * get another chunk of the body from client_side.
++ */
++static void
++icapReqModSendBodyChunk(int fd, char *bufnotused, size_t size, int errflag,
++ void *data)
++{
++ IcapStateData *icap = data;
++ debug(81, 3) ("icapReqModSendBodyChunk: FD %d wrote %d errflag %d.\n",
++ fd, (int) size, errflag);
++ if (errflag == COMM_ERR_CLOSING)
++ return;
++ if (errflag) {
++ icapEntryError(icap, ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR,
++ errno);
++ comm_close(fd);
++ return;
++ }
++ clientReadBody(icap->request,
++ memAllocate(MEM_8K_BUF), 8192, icapReqModBodyHandler, icap);
++}
++
++/*
++ * icapReqModBodyHandler
++ *
++ * Called after Squid gets a chunk of the request entity from the
++ * client side. The body is chunkified and passed to comm_write.
++ * The comm_write callback depends on whether or not this is the
++ * last chunk.
++ */
++static void
++icapReqModBodyHandler(char *buf, ssize_t size, void *data)
++{
++ IcapStateData *icap = data;
++ MemBuf mb;
++ CWCB *theCallback = icapReqModSendBodyChunk;
++ if (size < 0) {
++ debug(81, 1) ("icapReqModBodyHandler: %s\n", xstrerror());
++ memFree8K(buf);
++ return;
++ }
++ memBufDefInit(&mb);
++ debug(81, 3) ("icapReqModBodyHandler: writing chunk size %d\n", size);
++ memBufPrintf(&mb, "%x\r\n", size);
++ if (size)
++ memBufAppend(&mb, buf, size);
++ else
++ theCallback = icapSendReqModDone;
++ memBufAppend(&mb, crlf, 2);
++ memFree8K(buf);
++ comm_write_mbuf(icap->icap_fd, mb, theCallback, icap);
++}
++
++/*
++ * icapReqModReadHttpBody
++ *
++ * The read handler for the client's HTTP connection when reading
++ * message bodies. Called by comm_select().
++ */
++static void
++icapReqModReadHttpBody(int fd, void *data)
++{
++ IcapStateData *icap = data;
++ int len;
++ debug(81, 3) ("icapReqModReadHttpBody: FD %d called\n", fd);
++ len = memBufRead(fd, &icap->chunk_buf);
++ debug(81, 3) ("icapReqModReadHttpBody: read returns %d\n", len);
++ if (len < 0) {
++ debug(81, 3) ("icapReqModReadHttpBody: FD %d %s\n", fd, xstrerror());
++ if (!ignoreErrno(errno))
++ icap->flags.reqmod_http_entity_eof = 1;
++ } else if (0 == len) {
++ debug(81, 3) ("icapReqModReadHttpBody: FD %d EOF\n", fd);
++ icap->flags.reqmod_http_entity_eof = 1;
++ } else {
++ fd_bytes(fd, len, FD_READ);
++ kb_incr(&statCounter.icap.all.kbytes_in, len);
++ icap->reqmod.http_entity.bytes_read +=
++ icapParseChunkedBody(icap,
++ icapReqModMemBufAppend, &icap->reqmod.http_entity.buf);
++ }
++ if (icap->reqmod.http_entity.bytes_read >= icap->request->content_length)
++ icap->flags.reqmod_http_entity_eof = 1;
++
++ if (!icap->flags.reqmod_http_entity_eof)
++ commSetSelect(fd, COMM_SELECT_READ, icapReqModReadHttpBody, icap, 0);
++ /*
++ * Notify the other side if it is waiting for data from us
++ */
++ debug(81, 3) ("%s:%d http_entity.callback=%p\n", __FILE__, __LINE__,
++ icap->reqmod.http_entity.callback);
++ debug(81, 3) ("%s:%d http_entity.buf.size=%d\n", __FILE__, __LINE__,
++ icap->reqmod.http_entity.buf.size);
++ if (icap->reqmod.http_entity.callback && icap->reqmod.http_entity.buf.size) {
++ icapReqModPassHttpBody(icap,
++ icap->reqmod.http_entity.callback_buf,
++ icap->reqmod.http_entity.callback_bufsize,
++ icap->reqmod.http_entity.callback,
++ icap->reqmod.http_entity.callback_data);
++ icap->reqmod.http_entity.callback = NULL;
++ cbdataUnlock(icap->reqmod.http_entity.callback_data);
++
++ }
++}
++
++/*
++ * icapReqModPassHttpBody
++ *
++ * Called from http.c after request headers have been sent.
++ * This function feeds the http.c module chunks of the request
++ * body that were stored in the http_entity.buf MemBuf.
++ */
++static void
++icapReqModPassHttpBody(IcapStateData * icap, char *buf, size_t size,
++ CBCB * callback, void *cbdata)
++{
++ debug(81, 3) ("icapReqModPassHttpBody: called\n");
++ if (!buf) {
++ debug(81, 1) ("icapReqModPassHttpBody: FD %d called with %p, %d, %p (request aborted)\n",
++ icap->icap_fd, buf, (int) size, cbdata);
++ comm_close(icap->icap_fd);
++ return;
++ }
++ if (!cbdataValid(cbdata)) {
++ debug(81,
++ 1)
++ ("icapReqModPassHttpBody: FD %d callback data invalid, closing\n",
++ icap->icap_fd);
++ comm_close(icap->icap_fd); /*It is better to be sure that the connection will be closed..... */
++ /*icapReqModKeepAliveOrClose(icap); */
++ return;
++ }
++ debug(81, 3) ("icapReqModPassHttpBody: entity buf size = %d\n",
++ icap->reqmod.http_entity.buf.size);
++ if (icap->reqmod.http_entity.buf.size) {
++ int copy_sz = icap->reqmod.http_entity.buf.size;
++ if (copy_sz > size)
++ copy_sz = size;
++ xmemcpy(buf, icap->reqmod.http_entity.buf.buf, copy_sz);
++ /* XXX don't let Alex see this ugliness */
++ xmemmove(icap->reqmod.http_entity.buf.buf,
++ icap->reqmod.http_entity.buf.buf + copy_sz,
++ icap->reqmod.http_entity.buf.size - copy_sz);
++ icap->reqmod.http_entity.buf.size -= copy_sz;
++ debug(81, 3) ("icapReqModPassHttpBody: giving %d bytes to other side\n",
++ copy_sz);
++ callback(buf, copy_sz, cbdata);
++ debug(81, 3) ("icapReqModPassHttpBody: entity buf size now = %d\n",
++ icap->reqmod.http_entity.buf.size);
++ return;
++ }
++ if (icap->flags.reqmod_http_entity_eof) {
++ debug(81, 3) ("icapReqModPassHttpBody: signalling EOF\n");
++ callback(buf, 0, cbdata);
++ icapReqModKeepAliveOrClose(icap);
++ return;
++ }
++ /*
++ * We have no data for the other side at this point. Save all
++ * these values and use them when we do have data.
++ */
++ assert(NULL == icap->reqmod.http_entity.callback);
++ icap->reqmod.http_entity.callback = callback;
++ icap->reqmod.http_entity.callback_data = cbdata;
++ icap->reqmod.http_entity.callback_buf = buf;
++ icap->reqmod.http_entity.callback_bufsize = size;
++ cbdataLock(icap->reqmod.http_entity.callback_data);
++}
++
++/*
++ * Body reader handler for use with request->body_reader function
++ * Simple a wrapper for icapReqModPassHttpBody function
++ */
++
++static void
++icapReqModBodyReader(request_t * request, char *buf, size_t size,
++ CBCB * callback, void *cbdata)
++{
++ IcapStateData *icap = request->body_reader_data;
++ icapReqModPassHttpBody(icap, buf, size, callback, cbdata);
++}
++
++/*
++ * icapReqModMemBufAppend
++ *
++ * stupid wrapper to eliminate compiler warnings
++ */
++static void
++icapReqModMemBufAppend(void *data, const char *buf, ssize_t size)
++{
++ memBufAppend(data, buf, size);
++}
+Index: src/icap_respmod.c
+===================================================================
+RCS file: src/icap_respmod.c
+diff -N src/icap_respmod.c
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ src/icap_respmod.c 25 Jun 2006 10:43:07 -0000 1.1.14.6
+@@ -0,0 +1,1065 @@
++
++/*
++ * $Id$
++ *
++ * DEBUG: section 81 Internet Content Adaptation Protocol (ICAP) Client
++ * AUTHOR: Geetha Manjunath, Hewlett Packard Company
++ *
++ * 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"
++
++static CWCB icapSendRespModDone;
++static PF icapRespModGobble;
++extern PF icapReadReply;
++static PF icapRespModReadReply;
++static void icapRespModKeepAliveOrClose(IcapStateData * icap);
++static int icapReadReply2(IcapStateData * icap);
++static void icapReadReply3(IcapStateData * icap);
++
++#define EXPECTED_ICAP_HEADER_LEN 256
++const char *crlf = "\r\n";
++
++static void
++getICAPRespModString(MemBuf * mb, int o1, int o2, int o3,
++ const char *client_addr, IcapStateData * icap, const icap_service * service)
++{
++ memBufPrintf(mb, "RESPMOD %s ICAP/1.0\r\nEncapsulated:", service->uri);
++ if (o1 >= 0)
++ memBufPrintf(mb, " req-hdr=%1d", o1);
++ if (o2 >= 0)
++ memBufPrintf(mb, ", res-hdr=%1d", o2);
++ if (o3 >= 0)
++ memBufPrintf(mb, ", res-body=%1d", o3);
++ else
++ memBufPrintf(mb, ", null-body=%1d", -o3);
++ memBufPrintf(mb, crlf);
++
++ if (service->flags.need_x_client_ip && Config.icapcfg.send_client_ip) {
++ memBufPrintf(mb, "X-Client-IP: %s\r\n", client_addr);
++ }
++ if (service->flags.need_x_server_ip && Config.icapcfg.send_server_ip)
++ icapAddOriginIP(mb, icap->request->host);
++
++ if ((service->flags.need_x_authenticated_user
++ && Config.icapcfg.send_auth_user)
++ && (icap->request->auth_user_request != NULL)) {
++ icapAddAuthUserHeader(mb, icap->request->auth_user_request);
++ }
++#if NOT_YET_FINISHED
++ if (Config.icapcfg.trailers) {
++ memBufPrintf(mb, "X-TE: trailers\r\n");
++ }
++#endif
++}
++
++static int
++buildRespModHeader(MemBuf * mb, IcapStateData * icap, char *buf,
++ ssize_t len, int theEnd)
++{
++ MemBuf mb_hdr;
++ char *client_addr;
++ int o2 = 0;
++ int o3 = 0;
++ int hlen;
++ int consumed;
++ icap_service *service;
++ HttpReply *r;
++
++ if (memBufIsNull(&icap->respmod.req_hdr_copy))
++ memBufDefInit(&icap->respmod.req_hdr_copy);
++
++ memBufAppend(&icap->respmod.req_hdr_copy, buf, len);
++
++ if (icap->respmod.req_hdr_copy.size > 4 && strncmp(icap->respmod.req_hdr_copy.buf, "HTTP/", 5)) {
++ debug(81, 3) ("buildRespModHeader: Non-HTTP-compliant header: '%s'\n", buf);
++ /*
++ *Possible we can consider that we did not have http responce headers
++ *(maybe HTTP 0.9 protocol), lets returning -1...
++ */
++ consumed = -1;
++ o2 = -1;
++ memBufDefInit(&mb_hdr);
++ httpBuildRequestPrefix(icap->request, icap->request,
++ icap->respmod.entry, &mb_hdr, icap->http_flags);
++ o3 = mb_hdr.size;
++ } else {
++
++ hlen = headersEnd(icap->respmod.req_hdr_copy.buf,
++ icap->respmod.req_hdr_copy.size);
++ debug(81, 3) ("buildRespModHeader: headersEnd = %d(%s)\n", hlen, buf);
++ if (0 == hlen)
++ return 0;
++
++ /*
++ * calc how many bytes from this 'buf' went towards the
++ * reply header.
++ */
++ consumed = hlen - (icap->respmod.req_hdr_copy.size - len);
++ debug(81, 3) ("buildRespModHeader: consumed = %d\n", consumed);
++
++
++ /*
++ * now, truncate our req_hdr_copy at the header end.
++ * this 'if' statement might be unncessary?
++ */
++ if (hlen < icap->respmod.req_hdr_copy.size)
++ icap->respmod.req_hdr_copy.size = hlen;
++
++ /* Copy request header */
++ memBufDefInit(&mb_hdr);
++ httpBuildRequestPrefix(icap->request, icap->request,
++ icap->respmod.entry, &mb_hdr, icap->http_flags);
++ o2 = mb_hdr.size;
++
++ /* Copy response header - Append to request header mbuffer */
++ memBufAppend(&mb_hdr,
++ icap->respmod.req_hdr_copy.buf, icap->respmod.req_hdr_copy.size);
++ o3 = mb_hdr.size;
++ }
++
++ service = icap->current_service;
++ assert(service);
++ client_addr = inet_ntoa(icap->request->client_addr);
++
++ r = httpReplyCreate();
++ httpReplyParse(r, icap->respmod.req_hdr_copy.buf,
++ icap->respmod.req_hdr_copy.size);
++ icap->respmod.res_body_sz = httpReplyBodySize(icap->request->method, r);
++ httpReplyDestroy(r);
++ if (icap->respmod.res_body_sz)
++ getICAPRespModString(mb, 0, o2, o3, client_addr, icap, service);
++ else
++ getICAPRespModString(mb, 0, o2, -o3, client_addr, icap, service);
++ if (Config.icapcfg.preview_enable)
++ if (icap->preview_size >= 0) {
++ memBufPrintf(mb, "Preview: %d\r\n", icap->preview_size);
++ icap->flags.preview_done = 0;
++ }
++ if (service->keep_alive) {
++ icap->flags.keep_alive = 1;
++ memBufAppend(mb, "Connection: keep-alive\r\n", 24);
++ } else {
++ icap->flags.keep_alive = 0;
++ memBufAppend(mb, "Connection: close\r\n", 19);
++ }
++ memBufAppend(mb, crlf, 2);
++ memBufAppend(mb, mb_hdr.buf, mb_hdr.size);
++ memBufClean(&mb_hdr);
++
++
++ return consumed;
++}
++
++
++void
++icapSendRespMod(IcapStateData * icap, char *buf, int len, int theEnd)
++{
++ MemBuf mb;
++#if ICAP_PREVIEW
++ int size;
++ const int preview_size = icap->preview_size;
++#endif
++ debug(81, 5) ("icapSendRespMod: FD %d, len %d, theEnd %d\n",
++ icap->icap_fd, len, theEnd);
++
++ if (icap->flags.no_content) {
++ /*
++ * ICAP server said there are no modifications to make, so
++ * just append this data to the StoreEntry
++ */
++ if (icap->respmod.resp_copy.size) {
++ /*
++ * first copy the data that we already sent to the ICAP server
++ */
++ memBufAppend(&icap->chunk_buf,
++ icap->respmod.resp_copy.buf, icap->respmod.resp_copy.size);
++ icap->respmod.resp_copy.size = 0;
++ }
++ debug(81, 5) ("icapSendRepMod: len=%d theEnd=%d write_pending=%d\n",
++ len, theEnd, icap->flags.write_pending);
++ if (len) {
++ /*
++ * also copy any new data from the HTTP side
++ */
++ memBufAppend(&icap->chunk_buf, buf, len);
++ }
++ (void) icapReadReply2(icap);
++ return;
++ }
++ if (theEnd) {
++ if (icap->respmod.res_body_sz)
++ icap->flags.send_zero_chunk = 1;
++ icap->flags.http_server_eof = 1;
++ }
++ /*
++ * httpReadReply is going to call us with a chunk and then
++ * right away again with an EOF if httpPconnTransferDone() is true.
++ * Since the first write is already dispatched, we'll have to
++ * hack this in somehow.
++ */
++ if (icap->flags.write_pending) {
++ debug(81, 3) ("icapSendRespMod: oops, write_pending=1\n");
++ assert(theEnd);
++ assert(len == 0);
++ return;
++ }
++ if (!cbdataValid(icap)) {
++ debug(81, 3) ("icapSendRespMod: failed to establish connection?\n");
++ return;
++ }
++ memBufDefInit(&mb);
++
++#if SUPPORT_ICAP_204 || ICAP_PREVIEW
++ /*
++ * make a copy of the response in case ICAP server gives us a 204
++ */
++ /*
++ * This piece of code is problematic for 204 responces outside preview.
++ * The icap->respmod.resp_copy continues to filled until we had responce
++ * If the icap server waits to gets all data before sends its responce
++ * then we are puting all downloading object to the main system memory.
++ * My opinion is that 204 responces outside preview must be disabled .....
++ * /chtsanti
++ */
++
++ if (len && icap->flags.copy_response) {
++ if (memBufIsNull(&icap->respmod.resp_copy))
++ memBufDefInit(&icap->respmod.resp_copy);
++ memBufAppend(&icap->respmod.resp_copy, buf, len);
++ }
++#endif
++
++ if (icap->sc == 0) {
++ // http connection has been closed without sending us anything
++ if (len == 0 && theEnd == 1) {
++ ErrorState *err;
++ err = errorCon(ERR_INVALID_RESP, HTTP_BAD_GATEWAY);
++ err->request = requestLink(icap->request);
++ errorAppendEntry(icap->respmod.entry, err);
++ comm_close(icap->icap_fd);
++ return;
++ }
++ /* No data sent yet. Start with headers */
++ if ((icap->sc = buildRespModHeader(&mb, icap, buf, len, theEnd)) > 0) {
++ buf += icap->sc;
++ len -= icap->sc;
++ }
++ /*
++ * Then we do not have http responce headers. All data (previous and those in buf)
++ * now are exist to icap->respmod.req_hdr_copy. Lets get them back.......
++ */
++ if (icap->sc < 0) {
++ memBufAppend(&icap->respmod.buffer,
++ icap->respmod.req_hdr_copy.buf,
++ icap->respmod.req_hdr_copy.size);
++ icap->sc = icap->respmod.req_hdr_copy.size;
++ icap->respmod.req_hdr_copy.size = 0;
++ buf = NULL;
++ len = 0;
++ }
++ }
++ if (0 == icap->sc) {
++ /* check again; bail if we're not ready to send ICAP/HTTP hdrs */
++ debug(81, 5) ("icapSendRespMod: dont have full HTTP response hdrs\n");
++ memBufClean(&mb);
++ return;
++ }
++#if ICAP_PREVIEW
++ if (preview_size < 0 || !Config.icapcfg.preview_enable) /* preview feature off */
++ icap->flags.preview_done = 1;
++
++ if (!icap->flags.preview_done) {
++ /* preview not yet sent */
++ if (icap->sc > 0 && icap->respmod.buffer.size <= preview_size
++ && len > 0) {
++ /* Try to collect at least preview_size+1 bytes */
++ /* By collecting one more byte than needed for preview we know best */
++ /* whether we have to send the ieof chunk extension */
++ size = icap->respmod.buffer.size + len;
++ if (size > preview_size + 1)
++ size = preview_size + 1;
++ size -= icap->respmod.buffer.size;
++ debug(81,
++ 3)
++ ("icapSendRespMod: FD %d: copy %d more bytes to preview buffer.\n",
++ icap->icap_fd, size);
++ memBufAppend(&icap->respmod.buffer, buf, size);
++ buf = ((char *) buf) + size;
++ len -= size;
++ }
++ if (icap->respmod.buffer.size > preview_size || theEnd) {
++ /* we got enough bytes for preview or this is the last call */
++ /* add preview preview now */
++ if (icap->respmod.buffer.size > 0) {
++ size = icap->respmod.buffer.size;
++ if (size > preview_size)
++ size = preview_size;
++ memBufPrintf(&mb, "%x\r\n", size);
++ memBufAppend(&mb, icap->respmod.buffer.buf, size);
++ memBufAppend(&mb, crlf, 2);
++ icap->sc += size;
++ }
++ if (icap->respmod.buffer.size <= preview_size) {
++ /* content length is less than preview size+1 */
++ if (icap->respmod.res_body_sz)
++ memBufAppend(&mb, "0; ieof\r\n\r\n", 11);
++ memBufReset(&icap->respmod.buffer); /* will now be used for other data */
++ } else {
++ char ch;
++ memBufAppend(&mb, "0\r\n\r\n", 5);
++ /* end of preview, wait for continue or 204 signal */
++ /* copy the extra byte and all other data to the icap buffer */
++ /* so that it can be handled next time */
++ ch = icap->respmod.buffer.buf[preview_size];
++ memBufReset(&icap->respmod.buffer); /* will now be used for other data */
++ memBufAppend(&icap->respmod.buffer, &ch, 1);
++ debug(81,
++ 3)
++ ("icapSendRespMod: FD %d: sending preview and keeping %d bytes in internal buf.\n",
++ icap->icap_fd, len + 1);
++ if (len > 0)
++ memBufAppend(&icap->respmod.buffer, buf, len);
++ }
++ icap->flags.preview_done = 1;
++ icap->flags.wait_for_preview_reply = 1;
++ }
++ } else if (icap->flags.wait_for_preview_reply) {
++ /* received new data while waiting for preview response */
++ /* add data to internal buffer and send later */
++ debug(81,
++ 3)
++ ("icapSendRespMod: FD %d: add %d more bytes to internal buf while waiting for preview-response.\n",
++ icap->icap_fd, len);
++ if (len > 0)
++ memBufAppend(&icap->respmod.buffer, buf, len);
++ /* do not send any data now while waiting for preview response */
++ /* but prepare for read more data on the HTTP connection */
++ memBufClean(&mb);
++ return;
++ } else
++#endif
++ {
++ /* after preview completed and ICAP preview response received */
++ /* there may still be some data in the buffer */
++ if (icap->respmod.buffer.size > 0) {
++ memBufPrintf(&mb, "%x\r\n", icap->respmod.buffer.size);
++ memBufAppend(&mb, icap->respmod.buffer.buf,
++ icap->respmod.buffer.size);
++ memBufAppend(&mb, crlf, 2);
++ icap->sc += icap->respmod.buffer.size;
++ memBufReset(&icap->respmod.buffer);
++ }
++ if (len > 0) {
++ memBufPrintf(&mb, "%x\r\n", len);
++ memBufAppend(&mb, buf, len);
++ memBufAppend(&mb, crlf, 2);
++ icap->sc += len;
++ }
++ if (icap->flags.send_zero_chunk) {
++ /* send zero end chunk */
++ icap->flags.send_zero_chunk = 0;
++ icap->flags.http_server_eof = 1;
++ memBufAppend(&mb, "0\r\n\r\n", 5);
++ }
++ /* wait for data coming from ICAP server as soon as we sent something */
++ /* but of course only until we got the response header */
++ if (!icap->flags.got_reply)
++ icap->flags.wait_for_reply = 1;
++ }
++ commSetTimeout(icap->icap_fd, -1, NULL, NULL);
++
++ if (!mb.size) {
++ memBufClean(&mb);
++ return;
++ }
++ debug(81, 5) ("icapSendRespMod: FD %d writing {%s}\n", icap->icap_fd,
++ mb.buf);
++ icap->flags.write_pending = 1;
++ comm_write_mbuf(icap->icap_fd, mb, icapSendRespModDone, icap);
++}
++
++static void
++icapRespModReadReply(int fd, void *data)
++{
++ IcapStateData *icap = data;
++ int version_major, version_minor;
++ const char *str_status;
++ int x;
++ int status = 0;
++ int isIcap = 0;
++ int directResponse = 0;
++ ErrorState *err;
++ const char *start;
++ const char *end;
++
++ debug(81, 5) ("icapRespModReadReply: FD %d data = %p\n", fd, data);
++ statCounter.syscalls.sock.reads++;
++
++ x = icapReadHeader(fd, icap, &isIcap);
++ if (x < 0) {
++ /* Did not find a proper ICAP response */
++ debug(81, 3) ("ICAP : Error path!\n");
++ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
++ err->request = requestLink(icap->request);
++ err->xerrno = errno;
++ errorAppendEntry(icap->respmod.entry, err);
++ comm_close(fd);
++ return;
++ }
++ if (x == 0) {
++ /*
++ * Waiting for more headers. Schedule new read hander, but
++ * don't reset timeout.
++ */
++ commSetSelect(fd, COMM_SELECT_READ, icapRespModReadReply, icap, 0);
++ return;
++ }
++ /*
++ * Parse the ICAP header
++ */
++ assert(icap->icap_hdr.size);
++ debug(81, 3) ("Parse icap header : <%s>\n", icap->icap_hdr.buf);
++ if ((status =
++ icapParseStatusLine(icap->icap_hdr.buf, icap->icap_hdr.size,
++ &version_major, &version_minor, &str_status)) < 0) {
++ debug(81, 1) ("BAD ICAP status line <%s>\n", icap->icap_hdr.buf);
++ /* is this correct in case of ICAP protocol error? */
++ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
++ err->request = requestLink(icap->request);
++ err->xerrno = errno;
++ errorAppendEntry(icap->respmod.entry, err);
++ comm_close(fd);
++ return;
++ };
++ /* OK here we have responce. Lets stop filling the
++ * icap->respmod.resp_copy buffer ....
++ */
++ icap->flags.copy_response = 0;
++
++ icapSetKeepAlive(icap, icap->icap_hdr.buf);
++#if ICAP_PREVIEW
++ if (icap->flags.wait_for_preview_reply) {
++ if (100 == status) {
++ debug(81, 5) ("icapRespModReadReply: 100 Continue received\n");
++ icap->flags.wait_for_preview_reply = 0;
++ /* if http_server_eof
++ * call again icapSendRespMod to handle data that
++ * was received while waiting for this ICAP response
++ * else let http to call icapSendRespMod when new data arrived
++ */
++ if (icap->flags.http_server_eof)
++ icapSendRespMod(icap, NULL, 0, 0);
++ /*
++ * reset the header to send the rest of the preview
++ */
++ if (!memBufIsNull(&icap->icap_hdr))
++ memBufReset(&icap->icap_hdr);
++
++ /*We do n't need it any more ....... */
++ if (!memBufIsNull(&icap->respmod.resp_copy))
++ memBufClean(&icap->respmod.resp_copy);
++
++ return;
++ }
++ if (204 == status) {
++ debug(81,
++ 5) ("icapRespModReadReply: 204 No modification received\n");
++ icap->flags.wait_for_preview_reply = 0;
++ }
++ }
++#endif /*ICAP_PREVIEW */
++
++#if SUPPORT_ICAP_204 || ICAP_PREVIEW
++ if (204 == status) {
++ debug(81, 3) ("got 204 status from ICAP server\n");
++ icapRespModKeepAliveOrClose(icap);
++
++ debug(81, 3) ("setting icap->flags.no_content\n");
++ icap->flags.no_content = 1;
++ /*
++ * copy the response already written to the ICAP server
++ */
++ debug(81, 3) ("copying %d bytes from resp_copy to chunk_buf\n",
++ icap->respmod.resp_copy.size);
++ memBufAppend(&icap->chunk_buf,
++ icap->respmod.resp_copy.buf, icap->respmod.resp_copy.size);
++ icap->respmod.resp_copy.size = 0;
++ if (icapReadReply2(icap) < 0)
++ icapStateFree(-1, icap);
++
++ /*
++ * XXX ideally want to clean icap->respmod.resp_copy here
++ * XXX ideally want to "close" ICAP server connection here
++ * OK do it....
++ */
++ if (!memBufIsNull(&icap->respmod.resp_copy))
++ memBufClean(&icap->respmod.resp_copy);
++ return;
++ }
++#endif
++ if (200 != status && 201 != status) {
++ debug(81, 1) ("Unsupported status '%d' from ICAP server\n", status);
++ /* Did not find a proper ICAP response */
++ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
++ err->request = requestLink(icap->request);
++ err->xerrno = errno;
++ errorAppendEntry(icap->respmod.entry, err);
++ comm_close(fd);
++ return;
++ }
++ if (icapFindHeader(icap->icap_hdr.buf, "Encapsulated:", &start, &end)) {
++ icapParseEncapsulated(icap, start, end);
++ } else {
++ debug(81,
++ 1)
++ ("WARNING: icapRespModReadReply() did not find 'Encapsulated' header\n");
++ }
++ if (icap->enc.res_hdr > -1)
++ directResponse = 1;
++ else if (icap->enc.res_body > -1)
++ directResponse = 1;
++ else
++ directResponse = 0;
++
++ /*
++ * "directResponse" is the normal case here. If we don't have
++ * a response header or body, it is an error.
++ */
++ if (!directResponse) {
++ /* Did not find a proper ICAP response */
++ debug(81, 3) ("ICAP : Error path!\n");
++ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
++ err->request = requestLink(icap->request);
++ err->xerrno = errno;
++ errorAppendEntry(icap->respmod.entry, err);
++ comm_close(fd);
++ return;
++ }
++ /* got the reply, no need to come here again */
++ icap->flags.wait_for_reply = 0;
++ icap->flags.got_reply = 1;
++ /* Next, gobble any data before the HTTP response starts */
++ if (icap->enc.res_hdr > -1)
++ icap->bytes_to_gobble = icap->enc.res_hdr;
++ commSetSelect(fd, COMM_SELECT_READ, icapRespModGobble, icap, 0);
++}
++
++
++/*
++ * Gobble up (read) some bytes until we get to the start of the body
++ */
++static void
++icapRespModGobble(int fd, void *data)
++{
++ IcapStateData *icap = data;
++ int len;
++ LOCAL_ARRAY(char, junk, SQUID_TCP_SO_RCVBUF);
++ debug(81, 3) ("icapRespModGobble: FD %d gobbling %d bytes\n", fd,
++ icap->bytes_to_gobble);
++ len = FD_READ_METHOD(fd, junk, icap->bytes_to_gobble);
++ debug(81, 3) ("icapRespModGobble: gobbled %d bytes\n", len);
++ if (len < 0) {
++ /* XXX error */
++ abort();
++ }
++ icap->bytes_to_gobble -= len;
++ if (icap->bytes_to_gobble)
++ commSetSelect(fd, COMM_SELECT_READ, icapRespModGobble, icap, 0);
++ else
++ icapReadReply(fd, icap);
++}
++
++
++static void
++icapSendRespModDone(int fd, char *bufnotused, size_t size, int errflag,
++ void *data)
++{
++ IcapStateData *icap = data;
++ ErrorState *err;
++
++ icap->flags.write_pending = 0;
++ debug(81, 5) ("icapSendRespModDone: FD %d: size %d: errflag %d.\n",
++ fd, size, errflag);
++ if (size > 0) {
++ fd_bytes(fd, size, FD_WRITE);
++ kb_incr(&statCounter.icap.all.kbytes_out, size);
++ }
++ if (errflag == COMM_ERR_CLOSING)
++ return;
++ if (errflag) {
++ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
++ err->xerrno = errno;
++ if (cbdataValid(icap))
++ err->request = requestLink(icap->request);
++ storeEntryReset(icap->respmod.entry);
++ errorAppendEntry(icap->respmod.entry, err);
++ comm_close(fd);
++ return;
++ }
++ if (EBIT_TEST(icap->respmod.entry->flags, ENTRY_ABORTED)) {
++ debug(81, 3) ("icapSendRespModDone: Entry Aborded\n");
++ comm_close(fd);
++ return;
++ }
++ if (icap->flags.send_zero_chunk) {
++ debug(81,
++ 3) ("icapSendRespModDone: I'm supposed to send zero chunk now\n");
++ icap->flags.send_zero_chunk = 0;
++ icapSendRespMod(icap, NULL, 0, 1);
++ return;
++ }
++ if (icap->flags.wait_for_preview_reply || icap->flags.wait_for_reply) {
++ /* Schedule reading the ICAP response */
++ debug(81,
++ 3)
++ ("icapSendRespModDone: FD %d: commSetSelect on read icapRespModReadReply.\n",
++ fd);
++ commSetSelect(fd, COMM_SELECT_READ, icapRespModReadReply, icap, 0);
++#if 1
++ commSetTimeout(fd, Config.Timeout.read, icapReadTimeout, icap);
++ commSetDefer(fd, fwdCheckDeferRead, icap->respmod.entry);
++#else
++ if (icap->flags.wait_for_preview_reply || icap->flags.http_server_eof) {
++ /*
++ * Set the read timeout only after all data has been sent
++ * or we are waiting for a preview response
++ * If the ICAP server does not return any data till all data
++ * has been sent, we are likely to hit the timeout for large
++ * HTTP bodies
++ */
++ commSetTimeout(fd, Config.Timeout.read, icapReadTimeout, icap);
++ }
++#endif
++ }
++}
++
++void
++icapConnectOver(int fd, int status, void *data)
++{
++ ErrorState *err;
++ IcapStateData *icap = data;
++ debug(81, 3) ("icapConnectOver: FD %d, status=%d\n", fd, status);
++ icap->flags.connect_pending = 0;
++ if (status < 0) {
++ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
++ err->xerrno = errno;
++ err->request = requestLink(icap->request);
++ errorAppendEntry(icap->respmod.entry, err);
++ comm_close(fd);
++ debug(81, 3) ("icapConnectOver: status < 0, unreachable=1\n");
++ icapOptSetUnreachable(icap->current_service);
++ return;
++ }
++ fd_table[fd].pconn.uses++;
++ fd_table[fd].pconn.type = 2;
++ commSetSelect(fd, COMM_SELECT_READ, icapRespModReadReply, icap, 0);
++}
++
++
++
++IcapStateData *
++icapRespModStart(icap_service_t type, request_t * request, StoreEntry * entry,
++ http_state_flags http_flags)
++{
++ IcapStateData *icap = NULL;
++ CNCB *theCallback = NULL;
++ icap_service *service = NULL;
++
++ debug(81, 3) ("icapRespModStart: type=%d\n", (int) type);
++ assert(type >= 0 && type < ICAP_SERVICE_MAX);
++
++ service = icapService(type, request);
++ if (!service) {
++ debug(81, 3) ("icapRespModStart: no service found\n");
++ return NULL; /* no service found */
++ }
++ if (service->unreachable) {
++ if (service->bypass) {
++ debug(81,
++ 5)
++ ("icapRespModStart: BYPASS because service unreachable: %s\n",
++ service->uri);
++ return NULL;
++ } else {
++ debug(81,
++ 5)
++ ("icapRespModStart: ERROR because service unreachable: %s\n",
++ service->uri);
++ return (IcapStateData *) - 1;
++ }
++ }
++ switch (type) {
++ /* TODO: When we support more than ICAP_SERVICE_RESPMOD_PRECACHE, we needs to change
++ * this switch, because callbacks isn't keep */
++ case ICAP_SERVICE_RESPMOD_PRECACHE:
++ theCallback = icapConnectOver;
++ break;
++ default:
++ fatalf("icapRespModStart: unsupported service type '%s'\n",
++ icap_service_type_str[type]);
++ break;
++ }
++
++ icap = icapAllocate();
++ if (!icap) {
++ debug(81, 3) ("icapRespModStart: icapAllocate() failed\n");
++ return NULL;
++ }
++ icap->request = requestLink(request);
++ icap->respmod.entry = entry;
++ if (entry)
++ storeLockObject(entry);
++ icap->http_flags = http_flags;
++ memBufDefInit(&icap->respmod.buffer);
++ memBufDefInit(&icap->chunk_buf);
++
++ icap->current_service = service;
++ icap->preview_size = service->preview;
++
++ /*
++ * Don't create socket to the icap server now, but only for the first
++ * packet receive from the http server. This will resolve all timeout
++ * between the web server and icap server.
++ */
++ debug(81, 3) ("icapRespModStart: setting connect_requested to 0\n");
++ icap->flags.connect_requested = 0;
++
++ /*
++ * make a copy the HTTP response that we send to the ICAP server in
++ * case it turns out to be a 204
++ */
++#ifdef SUPPORT_ICAP_204
++ icap->flags.copy_response = 1;
++#elif ICAP_PREVIEW
++ if (preview_size < 0 || !Config.icapcfg.preview_enable)
++ icap->flags.copy_response = 0;
++ else
++ icap->flags.copy_response = 1;
++#else
++ icap->flags.copy_response = 0;
++#endif
++
++ statCounter.icap.all.requests++;
++ debug(81, 3) ("icapRespModStart: returning %p\n", icap);
++ return icap;
++}
++
++static int
++icapHttpReplyHdrState(IcapStateData * icap)
++{
++ assert(icap);
++ if (NULL == icap->httpState)
++ return 0;
++ return icap->httpState->reply_hdr_state;
++}
++
++static void
++icapProcessHttpReplyHeader(IcapStateData * icap, const char *buf, int size)
++{
++ if (NULL == icap->httpState) {
++ icap->httpState = cbdataAlloc(HttpStateData);
++ icap->httpState->request = requestLink(icap->request);
++ icap->httpState->orig_request = requestLink(icap->request);
++ icap->httpState->entry = icap->respmod.entry;
++ storeLockObject(icap->httpState->entry); /* lock it */
++ }
++ httpProcessReplyHeader(icap->httpState, buf, size);
++ if (2 == icap->httpState->reply_hdr_state)
++ EBIT_CLR(icap->httpState->entry->flags, ENTRY_FWD_HDR_WAIT);
++}
++
++/*
++ * icapRespModKeepAliveOrClose
++ *
++ * Called when we are done reading from the ICAP server.
++ * Either close the connection or keep it open for a future
++ * transaction.
++ */
++static void
++icapRespModKeepAliveOrClose(IcapStateData * icap)
++{
++ int fd = icap->icap_fd;
++ if (fd < 0)
++ return;
++ debug(81, 3) ("%s:%d FD %d looks good, keeping alive\n", __FILE__, __LINE__,
++ fd);
++ commSetDefer(fd, NULL, NULL);
++ commSetTimeout(fd, -1, NULL, NULL);
++ commSetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0);
++ comm_remove_close_handler(fd, icapStateFree, icap);
++ icap->icap_fd = -1;
++ if (!icap->flags.keep_alive) {
++ debug(81, 3) ("%s:%d keep_alive not set, closing\n", __FILE__,
++ __LINE__);
++ comm_close(fd);
++ return;
++ } else {
++ pconnPush(fd, icap->current_service->hostname, icap->current_service->port, NULL, NULL, 0);
++ }
++}
++
++
++
++/*
++ * copied from httpPconnTransferDone
++ *
++ */
++static int
++icapPconnTransferDone(int fd, IcapStateData * icap)
++{
++ debug(81, 3) ("icapPconnTransferDone: FD %d\n", fd);
++ /*
++ * Be careful with 204 responses. Normally we are done when we
++ * see the zero-end chunk, but that won't happen for 204s, so we
++ * use an EOF indicator on the HTTP side instead.
++ */
++ if (icap->flags.no_content && icap->flags.http_server_eof) {
++ debug(81, 5) ("icapPconnTransferDone: no content, ret 1\n");
++ return 1;
++ }
++ if (icapHttpReplyHdrState(icap) != 2) {
++ debug(81,
++ 5) ("icapPconnTransferDone: didn't see end of HTTP hdrs, ret 0\n");
++ return 0;
++ }
++ if (icap->enc.null_body > -1) {
++ debug(81, 5) ("icapPconnTransferDone: no message body, ret 1\n");
++ return 1;
++ }
++ if (icap->chunk_size == -2) { //AI: was != -2 ; and change content with bottom
++ /* zero end chunk reached */
++ debug(81, 5) ("icapPconnTransferDone: got zero end chunk\n");
++ return 1;
++ }
++ debug(81, 5) ("icapPconnTransferDone: didnt get zero end chunk yet\n"); //AI: change with second top condition
++
++ return 0;
++}
++
++static int
++icapExpectedHttpReplyHdrSize(IcapStateData * icap)
++{
++ if (icap->enc.res_body > -1 && icap->enc.res_hdr > -1)
++ return (icap->enc.res_body - icap->enc.res_hdr);
++ if (icap->enc.null_body > -1 && icap->enc.res_hdr > -1)
++ return icap->enc.null_body - icap->enc.res_hdr;
++ /*The case we did not get res_hdr ..... */
++ if (icap->enc.res_body > -1)
++ return icap->enc.res_body;
++ if (icap->enc.null_body > -1)
++ return icap->enc.null_body;
++ return -1;
++}
++
++/*
++ * copied from httpReadReply()
++ *
++ * by the time this is called, the ICAP headers have already
++ * been read.
++ */
++void
++icapReadReply(int fd, void *data)
++{
++ IcapStateData *icap = data;
++ StoreEntry *entry = icap->respmod.entry;
++ const request_t *request = icap->request;
++ int len;
++ debug(81, 5) ("icapReadReply: FD %d: icap %p.\n", fd, data);
++ if (icap->flags.no_content && !icap->flags.http_server_eof) { //AI
++
++ return;
++ }
++ if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
++ comm_close(fd);
++ return;
++ }
++ errno = 0;
++ statCounter.syscalls.sock.reads++;
++ len = memBufRead(fd, &icap->chunk_buf);
++ debug(81, 5) ("icapReadReply: FD %d: len %d.\n", fd, len);
++ if (len > 0) {
++ fd_bytes(fd, len, FD_READ);
++ kb_incr(&statCounter.icap.all.kbytes_in, len);
++ commSetTimeout(fd, Config.Timeout.read, icapReadTimeout, icap);
++ if (icap->chunk_buf.size < icap->chunk_buf.capacity) {
++ *(icap->chunk_buf.buf + icap->chunk_buf.size) = '\0';
++ debug(81, 9) ("{%s}\n", icap->chunk_buf.buf);
++ }
++ }
++ if (len <= 0) {
++ debug(81, 2) ("icapReadReply: FD %d: read failure: %s.\n",
++ fd, xstrerror());
++ if (ignoreErrno(errno)) {
++ debug(81, 2) ("icapReadReply: FD %d: ignored errno\n", fd);
++ commSetSelect(fd, COMM_SELECT_READ, icapReadReply, icap, 0);
++ } else if (entry->mem_obj->inmem_hi == 0) {
++ ErrorState *err;
++ debug(81, 2) ("icapReadReply: FD %d: generating error page\n", fd);
++ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
++ err->request = requestLink((request_t *) request);
++ err->xerrno = errno;
++ errorAppendEntry(entry, err);
++ comm_close(fd);
++ } else {
++ debug(81, 2) ("icapReadReply: FD %d: just calling comm_close()\n",
++ fd);
++ comm_close(fd);
++ }
++ return;
++ }
++ if (icapReadReply2(icap) < 0)
++ comm_close(fd);
++}
++
++static int
++icapReadReply2(IcapStateData * icap)
++{
++ StoreEntry *entry = icap->respmod.entry;
++ const request_t *request = icap->request;
++ debug(81, 3) ("icapReadReply2\n");
++ if (icap->chunk_buf.size == 0 && entry->mem_obj->inmem_hi == 0) {
++ ErrorState *err;
++ err = errorCon(ERR_ZERO_SIZE_OBJECT, HTTP_SERVICE_UNAVAILABLE);
++ err->xerrno = errno;
++ err->request = requestLink((request_t *) request);
++ errorAppendEntry(entry, err);
++ icap->flags.http_server_eof = 1;
++ return -1;
++ }
++ if (icap->chunk_buf.size == 0) {
++ /* Retrieval done. */
++ if (icapHttpReplyHdrState(icap) < 2)
++ icapProcessHttpReplyHeader(icap, icap->chunk_buf.buf,
++ icap->chunk_buf.size);
++ icap->flags.http_server_eof = 1;
++ icapReadReply3(icap);
++ return 0;
++ }
++ if (icapHttpReplyHdrState(icap) == 0) {
++ int expect = icapExpectedHttpReplyHdrSize(icap);
++ int so_far = icap->http_header_bytes_read_so_far;
++ int needed = expect - so_far;
++ debug(81, 3) ("expect=%d\n", expect);
++ debug(81, 3) ("so_far=%d\n", so_far);
++ debug(81, 3) ("needed=%d\n", needed);
++ assert(needed < 0 || needed >= 0);
++ if (0 > expect) {
++ icapProcessHttpReplyHeader(icap,
++ icap->chunk_buf.buf, icap->chunk_buf.size);
++ } else if (0 == expect) {
++ /*
++ * this icap reply doesn't give us new HTTP headers
++ * so we must copy them from our copy
++ */
++ debug(81, 1) ("WARNING: untested code at %s:%d\n", __FILE__,
++ __LINE__);
++ if (icap->respmod.req_hdr_copy.size) { /*For HTTP 0.9 we do not have headers */
++ storeAppend(entry,
++ icap->respmod.req_hdr_copy.buf,
++ icap->respmod.req_hdr_copy.size);
++ }
++ icapProcessHttpReplyHeader(icap, icap->chunk_buf.buf,
++ icap->chunk_buf.size);
++ assert(icapHttpReplyHdrState(icap) == 2);
++ icap->chunk_size = 0; /*we are ready to read chunks of data now.... */
++ } else if (needed) {
++ icapProcessHttpReplyHeader(icap,
++ icap->chunk_buf.buf, icap->chunk_buf.size);
++ if (icap->chunk_buf.size >= needed) {
++ storeAppend(entry, icap->chunk_buf.buf, needed);
++ so_far += needed;
++ xmemmove(icap->chunk_buf.buf,
++ icap->chunk_buf.buf + needed,
++ icap->chunk_buf.size - needed);
++ icap->chunk_buf.size -= needed;
++ assert(icapHttpReplyHdrState(icap) == 2);
++ icap->chunk_size = 0;
++ } else {
++ /*
++ * We don't have the full HTTP reply headers yet, so keep
++ * the partial reply buffered in 'chunk_buf' and wait
++ * for more.
++ */
++ debug(81, 3) ("We don't have full Http headers.Schedule a new read\n");
++ commSetSelect(icap->icap_fd, COMM_SELECT_READ, icapReadReply, icap, 0);
++ }
++ }
++ icap->http_header_bytes_read_so_far = so_far;
++ }
++ debug(81, 3) ("%s:%d: icap->chunk_buf.size=%d\n", __FILE__, __LINE__,
++ (int) icap->chunk_buf.size);
++ debug(81, 3) ("%s:%d: flags.no_content=%d\n", __FILE__, __LINE__,
++ icap->flags.no_content);
++ if (icap->flags.no_content) {
++ /* data from http.c is not chunked */
++ if (!EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
++ debug(81, 3) ("copying %d bytes from chunk_buf to entry\n",
++ icap->chunk_buf.size);
++ storeAppend(entry, icap->chunk_buf.buf, icap->chunk_buf.size);
++ icap->chunk_buf.size = 0;
++ }
++ } else if (2 == icapHttpReplyHdrState(icap)) {
++ if (icap->chunk_buf.size)
++ icapParseChunkedBody(icap, (STRCB *) storeAppend, entry);
++ }
++ icapReadReply3(icap);
++ return 0;
++}
++
++static void
++icapReadReply3(IcapStateData * icap)
++{
++ StoreEntry *entry = icap->respmod.entry;
++ int fd = icap->icap_fd;
++ debug(81, 3) ("icapReadReply3\n");
++ if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
++ debug(81, 3) ("icapReadReply3: Entry Aborded\n");
++ if (icap->flags.no_content)
++ icapStateFree(-1, icap);
++ else
++ comm_close(fd);
++ } else if (icapPconnTransferDone(fd, icap)) {
++ storeComplete(entry);
++ if (icap->flags.no_content)
++ icapStateFree(-1, icap);
++ else {
++ icapRespModKeepAliveOrClose(icap);
++ icapStateFree(-1, icap);
++ }
++ } else if (!icap->flags.no_content) {
++ /* Wait for EOF condition */
++ commSetSelect(fd, COMM_SELECT_READ, icapReadReply, icap, 0);
++ debug(81,
++ 3)
++ ("icapReadReply3: Going to read mode data throught icapReadReply\n");
++ } else {
++ debug(81, 3) ("icapReadReply3: Nothing\n");
++ }
++}
+Index: src/main.c
+===================================================================
+RCS file: /cvsroot/squid/squid/src/main.c,v
+retrieving revision 1.67
+retrieving revision 1.45.4.7
+diff -p -u -b -r1.67 -r1.45.4.7
+--- src/main.c 30 Jul 2006 23:52:54 -0000 1.67
++++ src/main.c 3 Aug 2006 17:16:04 -0000 1.45.4.7
+@@ -391,6 +391,9 @@ mainReconfigure(void)
+ #else
+ idnsShutdown();
+ #endif
++#ifdef HS_FEAT_ICAP
++ icapClose();
++#endif
+ redirectShutdown();
+ locationRewriteShutdown();
+ authenticateShutdown();
+@@ -422,6 +425,9 @@ mainReconfigure(void)
+ #endif
+ redirectInit();
+ locationRewriteInit();
++#ifdef HS_FEAT_ICAP
++ icapInit();
++#endif
+ authenticateInit(&Config.authConfig);
+ externalAclInit();
+ #if USE_WCCP
+@@ -565,6 +571,9 @@ mainInitialize(void)
+ redirectInit();
+ locationRewriteInit();
+ errorMapInit();
++#ifdef HS_FEAT_ICAP
++ icapInit();
++#endif
+ authenticateInit(&Config.authConfig);
+ externalAclInit();
+ useragentOpenLog();
+Index: src/mem.c
+===================================================================
+RCS file: /cvsroot/squid/squid/src/mem.c,v
+retrieving revision 1.27
+retrieving revision 1.24.4.3
+diff -p -u -b -r1.27 -r1.24.4.3
+--- src/mem.c 20 May 2006 22:50:55 -0000 1.27
++++ src/mem.c 26 May 2006 18:21:32 -0000 1.24.4.3
+@@ -353,6 +353,13 @@ memInit(void)
+ memDataInit(MEM_TLV, "storeSwapTLV", sizeof(tlv), 0);
+ memDataInit(MEM_SWAP_LOG_DATA, "storeSwapLogData", sizeof(storeSwapLogData), 0);
+
++#ifdef HS_FEAT_ICAP
++ memDataInit(MEM_ICAP_OPT_DATA, "IcapOptData", sizeof(IcapOptData), 0);
++ memDataInit(MEM_ICAP_SERVICE_LIST, "icap_service_list", sizeof(icap_service_list), 0);
++ memDataInit(MEM_ICAP_CLASS, "icap_class", sizeof(icap_class), 0);
++ memDataInit(MEM_ICAP_ACCESS, "icap_access", sizeof(icap_access), 0);
++#endif
++
+ /* init string pools */
+ for (i = 0; i < mem_str_pool_count; i++) {
+ StrPools[i].pool = memPoolCreate(StrPoolsAttrs[i].name, StrPoolsAttrs[i].obj_size);
+Index: src/mk-string-arrays.pl
+===================================================================
+RCS file: /cvsroot/squid/squid/src/mk-string-arrays.pl,v
+retrieving revision 1.2
+retrieving revision 1.2.180.1
+diff -p -u -b -r1.2 -r1.2.180.1
+--- src/mk-string-arrays.pl 23 Oct 2000 15:04:21 -0000 1.2
++++ src/mk-string-arrays.pl 17 May 2006 17:58:01 -0000 1.2.180.1
+@@ -16,6 +16,7 @@ $pat{'err_type'} = "err_type_str";
+ $pat{'icp_opcode'} = "icp_opcode_str";
+ $pat{'swap_log_op'} = "swap_log_op_str";
+ $pat{'lookup_t'} = "lookup_t_str";
++$pat{'icap_service_t'} = "icap_service_type_str";
+
+ $state = 0; # start state
+ while (<>) {
+Index: src/pconn.c
+===================================================================
+RCS file: /cvsroot/squid/squid/src/pconn.c,v
+retrieving revision 1.10
+retrieving revision 1.9.4.2
+diff -p -u -b -r1.10 -r1.9.4.2
+--- src/pconn.c 22 May 2006 22:06:12 -0000 1.10
++++ src/pconn.c 26 May 2006 18:21:32 -0000 1.9.4.2
+@@ -46,6 +46,9 @@ struct _pconn {
+ #define PCONN_HIST_SZ (1<<16)
+ int client_pconn_hist[PCONN_HIST_SZ];
+ int server_pconn_hist[PCONN_HIST_SZ];
++#ifdef HS_FEAT_ICAP
++int icap_server_pconn_hist[PCONN_HIST_SZ];
++#endif
+
+ static PF pconnRead;
+ static PF pconnTimeout;
+@@ -169,6 +172,20 @@ pconnHistDump(StoreEntry * e)
+ continue;
+ storeAppendPrintf(e, "\t%4d %9d\n", i, server_pconn_hist[i]);
+ }
++#ifdef HS_FEAT_ICAP
++ storeAppendPrintf(e,
++ "\n"
++ "ICAP-server persistent connection counts:\n"
++ "\n"
++ "\treq/\n"
++ "\tconn count\n"
++ "\t---- ---------\n");
++ for (i = 0; i < PCONN_HIST_SZ; i++) {
++ if (icap_server_pconn_hist[i] == 0)
++ continue;
++ storeAppendPrintf(e, "\t%4d %9d\n", i, icap_server_pconn_hist[i]);
++ }
++#endif
+ }
+
+ /* ========== PUBLIC FUNCTIONS ============================================ */
+@@ -183,6 +200,9 @@ pconnInit(void)
+ for (i = 0; i < PCONN_HIST_SZ; i++) {
+ client_pconn_hist[i] = 0;
+ server_pconn_hist[i] = 0;
++#ifdef HS_FEAT_ICAP
++ icap_server_pconn_hist[i] = 0;
++#endif
+ }
+ pconn_data_pool = memPoolCreate("pconn_data", sizeof(struct _pconn));
+ pconn_fds_pool = memPoolCreate("pconn_fds", PCONN_FDS_SZ * sizeof(int));
+@@ -265,11 +285,15 @@ pconnHistCount(int what, int i)
+ {
+ if (i >= PCONN_HIST_SZ)
+ i = PCONN_HIST_SZ - 1;
+- /* what == 0 for client, 1 for server */
++ /* what == 0 for client, 1 for server, 2 for ICAP server */
+ if (what == 0)
+ client_pconn_hist[i]++;
+ else if (what == 1)
+ server_pconn_hist[i]++;
++#ifdef HS_FEAT_ICAP
++ else if (what == 2)
++ icap_server_pconn_hist[i]++;
++#endif
+ else
+ assert(0);
+ }
+Index: src/protos.h
+===================================================================
+RCS file: /cvsroot/squid/squid/src/protos.h,v
+retrieving revision 1.118
+retrieving revision 1.74.4.8
+diff -p -u -b -r1.118 -r1.74.4.8
+--- src/protos.h 30 Jul 2006 23:52:54 -0000 1.118
++++ src/protos.h 3 Aug 2006 17:16:05 -0000 1.74.4.8
+@@ -295,6 +295,8 @@ extern void whoisStart(FwdState *);
+ /* http.c */
+ extern int httpCachable(method_t);
+ extern void httpStart(FwdState *);
++extern void httpParseReplyHeaders(const char *, http_reply *);
++extern void httpProcessReplyHeader(HttpStateData *, const char *, int);
+ extern int httpBuildRequestPrefix(request_t * request,
+ request_t * orig_request,
+ StoreEntry * entry,
+@@ -617,6 +619,7 @@ extern void memBufVPrintf(MemBuf * mb, c
+ extern FREE *memBufFreeFunc(MemBuf * mb);
+ /* puts report on MemBuf _module_ usage into mb */
+ extern void memBufReport(MemBuf * mb);
++extern int memBufRead(int fd, MemBuf * mb);
+
+ extern char *mime_get_header(const char *mime, const char *header);
+ extern char *mime_get_header_field(const char *mime, const char *name, const char *prefix);
+@@ -1409,4 +1412,53 @@ void storeLocateVaryDone(VaryData * data
+ void storeLocateVary(StoreEntry * e, int offset, const char *vary_data, String accept_encoding, STLVCB * callback, void *cbdata);
+ void storeAddVary(const char *url, const char *log_url, const method_t method, const cache_key * key, const char *etag, const char *vary, const char *vary_headers, const char *accept_encoding);
+
++#ifdef HS_FEAT_ICAP
++/*
++ * icap_common.c
++ */
++void icapInit(void);
++void icapClose(void);
++void icapParseEncapsulated(IcapStateData *, const char *, const char *);
++icap_service *icapService(icap_service_t, request_t *);
++int icapConnect(IcapStateData *, CNCB *);
++IcapStateData *icapAllocate(void);
++PF icapStateFree;
++PF icapConnectTimeout;
++PF icapReadTimeout;
++icap_service_t icapServiceToType(const char *);
++const char *icapServiceToStr(const icap_service_t);
++int icapCheckAcl(clientHttpRequest *);
++size_t icapLineLength(const char *, int);
++int icapReadHeader(int, IcapStateData *, int *);
++int icapFindHeader(const char *, const char *, const char **, const char **);
++int icapParseKeepAlive(const IcapStateData *, const char *, const char *);
++void icapSetKeepAlive(IcapStateData * icap, const char *hdrs);
++size_t icapParseChunkedBody(IcapStateData *, STRCB *, void *);
++void icapAddAuthUserHeader(MemBuf *, auth_user_request_t *);
++int icapParseStatusLine(const char *, int, int *, int *, const char **);
++
++/*
++ * icap_respmod.c
++ */
++IcapStateData *icapRespModStart(icap_service_t, request_t *, StoreEntry *, http_state_flags);
++void icapSendRespMod(IcapStateData *, char *, int, int);
++CNCB icapConnectOver;
++
++/*
++ * icap_reqmod.c
++ */
++IcapStateData *icapReqModStart(icap_service*, const char *, request_t *, int, struct timeval, struct in_addr, void *);
++
++/* icap_opt.c */
++void icapOptInit(void);
++void icapOptShutdown(void);
++void icapOptSetUnreachable(icap_service * s);
++
++/* X-Server-IP support */
++void icapAddOriginIP(MemBuf *, const char *);
++
++/* for debugging purposes only */
++void dump_icap_config(IcapConfig * cfg);
++#endif
++
+ #endif /* SQUID_PROTOS_H */
+Index: src/squid.h
+===================================================================
+RCS file: /cvsroot/squid/squid/src/squid.h,v
+retrieving revision 1.34
+retrieving revision 1.24.8.5
+diff -p -u -b -r1.34 -r1.24.8.5
+--- src/squid.h 8 Jun 2006 13:51:37 -0000 1.34
++++ src/squid.h 12 Jun 2006 17:56:59 -0000 1.24.8.5
+@@ -38,6 +38,14 @@
+ #include "config.h"
+
+ /*
++ * experimental defines for ICAP
++ */
++#ifdef HS_FEAT_ICAP
++#define ICAP_PREVIEW 1
++#define SUPPORT_ICAP_204 0
++#endif
++
++/*
+ * On some systems, FD_SETSIZE is set to something lower than the
+ * actual number of files which can be opened. IRIX is one case,
+ * NetBSD is another. So here we increase FD_SETSIZE to our
+Index: src/stat.c
+===================================================================
+RCS file: /cvsroot/squid/squid/src/stat.c,v
+retrieving revision 1.34
+retrieving revision 1.26.8.7
+diff -p -u -b -r1.34 -r1.26.8.7
+--- src/stat.c 29 Jul 2006 17:50:57 -0000 1.34
++++ src/stat.c 3 Aug 2006 17:16:06 -0000 1.26.8.7
+@@ -787,6 +787,17 @@ statAvgDump(StoreEntry * sentry, int min
+ storeAppendPrintf(sentry, "server.other.kbytes_out = %f/sec\n",
+ XAVG(server.other.kbytes_out.kb));
+
++#ifdef HS_FEAT_ICAP
++ storeAppendPrintf(sentry, "icap.all.requests = %f/sec\n",
++ XAVG(icap.all.requests));
++ storeAppendPrintf(sentry, "icap.all.errors = %f/sec\n",
++ XAVG(icap.all.errors));
++ storeAppendPrintf(sentry, "icap.all.kbytes_in = %f/sec\n",
++ XAVG(icap.all.kbytes_in.kb));
++ storeAppendPrintf(sentry, "icap.all.kbytes_out = %f/sec\n",
++ XAVG(icap.all.kbytes_out.kb));
++#endif
++
+ storeAppendPrintf(sentry, "icp.pkts_sent = %f/sec\n",
+ XAVG(icp.pkts_sent));
+ storeAppendPrintf(sentry, "icp.pkts_recv = %f/sec\n",
+@@ -1171,6 +1182,17 @@ statCountersDump(StoreEntry * sentry)
+ storeAppendPrintf(sentry, "server.other.kbytes_out = %d\n",
+ (int) f->server.other.kbytes_out.kb);
+
++#if HS_FEAT_ICAP
++ storeAppendPrintf(sentry, "icap.all.requests = %d\n",
++ (int) f->icap.all.requests);
++ storeAppendPrintf(sentry, "icap.all.errors = %d\n",
++ (int) f->icap.all.errors);
++ storeAppendPrintf(sentry, "icap.all.kbytes_in = %d\n",
++ (int) f->icap.all.kbytes_in.kb);
++ storeAppendPrintf(sentry, "icap.all.kbytes_out = %d\n",
++ (int) f->icap.all.kbytes_out.kb);
++#endif
++
+ storeAppendPrintf(sentry, "icp.pkts_sent = %d\n",
+ f->icp.pkts_sent);
+ storeAppendPrintf(sentry, "icp.pkts_recv = %d\n",
+@@ -1471,8 +1493,6 @@ statClientRequests(StoreEntry * s)
+ storeAppendPrintf(s, "\tme: %s:%d\n",
+ inet_ntoa(conn->me.sin_addr),
+ ntohs(conn->me.sin_port));
+- storeAppendPrintf(s, "\tnrequests: %d\n",
+- conn->nrequests);
+ storeAppendPrintf(s, "\tdefer: n %d, until %ld\n",
+ conn->defer.n, (long int) conn->defer.until);
+ }
+Index: src/store.c
+===================================================================
+RCS file: /cvsroot/squid/squid/src/store.c,v
+retrieving revision 1.35
+retrieving revision 1.21.10.7
+diff -p -u -b -r1.35 -r1.21.10.7
+--- src/store.c 17 Jul 2006 02:51:31 -0000 1.35
++++ src/store.c 22 Jul 2006 14:12:02 -0000 1.21.10.7
+@@ -1088,8 +1088,17 @@ storeAppend(StoreEntry * e, const char *
+ MemObject *mem = e->mem_obj;
+ assert(mem != NULL);
+ assert(len >= 0);
+- assert(e->store_status == STORE_PENDING);
+ mem->refresh_timestamp = squid_curtime;
++ debug(20, 3) ("storeAppend: '%s'\n", storeKeyText(e->hash.key));
++ if (e->store_status != STORE_PENDING) {
++ /*
++ * if we're not STORE_PENDING, then probably we got aborted
++ * and there should be NO clients on this entry
++ */
++ assert(EBIT_TEST(e->flags, ENTRY_ABORTED));
++ assert(e->mem_obj->nclients == 0);
++ return;
++ }
+ if (len) {
+ debug(20, 5) ("storeAppend: appending %d bytes for '%s'\n",
+ len,
+Index: src/structs.h
+===================================================================
+RCS file: /cvsroot/squid/squid/src/structs.h,v
+retrieving revision 1.126
+retrieving revision 1.81.4.8
+diff -p -u -b -r1.126 -r1.81.4.8
+--- src/structs.h 30 Jul 2006 23:52:55 -0000 1.126
++++ src/structs.h 3 Aug 2006 17:16:06 -0000 1.81.4.8
+@@ -423,6 +423,23 @@ struct _RemovalPolicySettings {
+ wordlist *args;
+ };
+
++#if HS_FEAT_ICAP
++struct _IcapConfig {
++ int onoff;
++ int preview_enable;
++ icap_service *service_head;
++ icap_class *class_head;
++ icap_access *access_head;
++ int preview_size;
++ int check_interval;
++ int send_client_ip;
++ int send_server_ip;
++ int send_auth_user;
++ char *auth_scheme;
++};
++
++#endif /* HS_FEAT_ICAP */
++
+ struct _SquidConfig {
+ struct {
+ squid_off_t maxSize;
+@@ -808,6 +825,9 @@ struct _SquidConfig {
+ #endif
+ time_t refresh_stale_window;
+ int umask;
++#ifdef HS_FEAT_ICAP
++ IcapConfig icapcfg;
++#endif
+ };
+
+ struct _SquidConfig2 {
+@@ -879,6 +899,10 @@ struct _fde {
+ comm_pending write_pending;
+ squid_off_t bytes_read;
+ squid_off_t bytes_written;
++ struct {
++ int uses;
++ int type;
++ } pconn;
+ int uses; /* ie # req's over persistent conn */
+ struct _fde_disk {
+ DWCB *wrt_handle;
+@@ -1075,6 +1099,131 @@ struct _http_state_flags {
+ unsigned int originpeer:1;
+ };
+
++#ifdef HS_FEAT_ICAP
++struct _IcapStateData {
++ request_t *request;
++ http_state_flags http_flags;
++ HttpStateData *httpState; /* needed to parse HTTP headers only */
++ int icap_fd;
++ int sc;
++ icap_service *current_service;
++ MemBuf icap_hdr;
++ struct {
++ int res_hdr;
++ int res_body;
++ int req_hdr;
++ int req_body;
++ int opt_body;
++ int null_body;
++ } enc;
++ int bytes_to_gobble;
++ int chunk_size;
++ MemBuf chunk_buf;
++ int preview_size;
++ squid_off_t fake_content_length;
++ int http_header_bytes_read_so_far;
++ struct {
++ const char *uri; /* URI for REQMODs */
++ int client_fd;
++ struct timeval start; /* for logging */
++ struct in_addr log_addr; /* for logging */
++ int hdr_state;
++ MemBuf hdr_buf;
++ void *client_cookie;
++ struct {
++ MemBuf buf;
++ CBCB *callback;
++ void *callback_data;
++ char *callback_buf;
++ size_t callback_bufsize;
++ squid_off_t bytes_read;
++ } http_entity;
++ } reqmod;
++ struct {
++ StoreEntry *entry;
++ MemBuf buffer;
++ MemBuf req_hdr_copy; /* XXX barf */
++ MemBuf resp_copy; /* XXX barf^max */
++ squid_off_t res_body_sz;
++ } respmod;
++ struct {
++ unsigned int connect_requested:1;
++ unsigned int connect_pending:1;
++ unsigned int write_pending:1;
++ unsigned int keep_alive:1;
++ unsigned int http_server_eof:1;
++ unsigned int send_zero_chunk:1;
++ unsigned int got_reply:1;
++ unsigned int wait_for_reply:1;
++ unsigned int wait_for_preview_reply:1;
++ unsigned int preview_done:1;
++ unsigned int copy_response:1;
++ unsigned int no_content:1;
++ unsigned int reqmod_http_entity_eof:1;
++ } flags;
++};
++
++struct _icap_service {
++ icap_service *next;
++ char *name; /* name to be used when referencing ths service */
++ char *uri; /* uri of server/service to use */
++ char *type_name; /* {req|resp}mod_{pre|post}cache */
++
++ char *hostname;
++ unsigned short int port;
++ char *resource;
++ icap_service_t type; /* parsed type */
++ icap_method_t method;
++ ushort bypass; /* flag: bypass allowed */
++ ushort unreachable; /* flag: set to 1 if options request fails */
++ IcapOptData *opt; /* temp data needed during opt request */
++ struct {
++ unsigned int allow_204:1;
++ unsigned int need_x_client_ip:1;
++ unsigned int need_x_server_ip:1;
++ unsigned int need_x_authenticated_user:1;
++ } flags;
++ int preview;
++ String istag;
++ String transfer_preview;
++ String transfer_ignore;
++ String transfer_complete;
++ int max_connections;
++ int options_ttl;
++ int keep_alive;
++};
++
++struct _icap_service_list {
++ icap_service_list *next;
++ icap_service *services[16];
++ int nservices; /* Number of services already used */
++ int last_service_used; /* Last services used, use to do a round robin */
++};
++
++struct _icap_class {
++ icap_class *next;
++ char *name;
++ wordlist *services;
++ icap_service_list *isl;
++ ushort hidden; /* for unnamed classes */
++};
++
++struct _icap_access {
++ icap_access *next;
++ char *service_name;
++ icap_class *class;
++ acl_access *access;
++};
++
++struct _IcapOptData {
++ char *buf;
++ off_t offset;
++ size_t size;
++ off_t headlen;
++};
++
++#endif
++
+ struct _HttpStateData {
+ StoreEntry *entry;
+ request_t *request;
+@@ -1086,10 +1235,14 @@ struct _HttpStateData {
+ int fd;
+ http_state_flags flags;
+ FwdState *fwd;
++#ifdef HS_FEAT_ICAP
++ struct _IcapStateData *icap_writer;
++#endif
+ char *body_buf;
+ int body_buf_sz;
+ };
+
++
+ struct _icpUdpData {
+ struct sockaddr_in address;
+ void *msg;
+@@ -1198,6 +1351,7 @@ struct _clientHttpRequest {
+ unsigned int internal:1;
+ unsigned int done_copying:1;
+ unsigned int purging:1;
++ unsigned int did_icap_reqmod:1;
+ unsigned int hit:1;
+ } flags;
+ struct {
+@@ -1206,6 +1360,9 @@ struct _clientHttpRequest {
+ } redirect;
+ dlink_node active;
+ squid_off_t maxBodySize;
++#if HS_FEAT_ICAP
++ IcapStateData *icap_reqmod;
++#endif
+ };
+
+ struct _ConnStateData {
+@@ -1873,6 +2030,9 @@ struct _request_t {
+ unsigned int done_etag:1; /* We have done clientProcessETag on this, don't attempt it again */
+ char *urlgroup; /* urlgroup, returned by redirectors */
+ char *peer_domain; /* Configured peer forceddomain */
++#if HS_FEAT_ICAP
++ icap_class *class;
++#endif
+ BODY_HANDLER *body_reader;
+ void *body_reader_data;
+ String extacl_log; /* String to be used for access.log purposes */
+@@ -1989,7 +2149,11 @@ struct _StatCounters {
+ kb_t kbytes_in;
+ kb_t kbytes_out;
+ } all , http, ftp, other;
+- } server;
++ }
++#if HS_FEAT_ICAP
++ icap,
++#endif
++ server;
+ struct {
+ int pkts_sent;
+ int queries_sent;
+Index: src/typedefs.h
+===================================================================
+RCS file: /cvsroot/squid/squid/src/typedefs.h,v
+retrieving revision 1.39
+retrieving revision 1.32.4.6
+diff -p -u -b -r1.39 -r1.32.4.6
+--- src/typedefs.h 30 Jul 2006 23:52:55 -0000 1.39
++++ src/typedefs.h 3 Aug 2006 17:16:07 -0000 1.32.4.6
+@@ -136,6 +136,15 @@ typedef struct _HttpHeaderStat HttpHeade
+ typedef struct _HttpBody HttpBody;
+ typedef struct _HttpReply HttpReply;
+ typedef struct _HttpStateData HttpStateData;
++#ifdef HS_FEAT_ICAP
++typedef struct _IcapStateData IcapStateData;
++typedef struct _IcapConfig IcapConfig;
++typedef struct _icap_service icap_service;
++typedef struct _icap_service_list icap_service_list;
++typedef struct _icap_class icap_class;
++typedef struct _icap_access icap_access;
++typedef struct _IcapOptData IcapOptData;
++#endif
+ typedef struct _icpUdpData icpUdpData;
+ typedef struct _clientHttpRequest clientHttpRequest;
+ typedef struct _ConnStateData ConnStateData;
+Index: src/url.c
+===================================================================
+RCS file: /cvsroot/squid/squid/src/url.c,v
+retrieving revision 1.17
+retrieving revision 1.14.10.4
+diff -p -u -b -r1.17 -r1.14.10.4
+--- src/url.c 17 Jun 2006 23:51:19 -0000 1.17
++++ src/url.c 28 Jun 2006 21:12:01 -0000 1.14.10.4
+@@ -103,6 +103,9 @@ const char *ProtocolStr[] =
+ "whois",
+ "internal",
+ "https",
++#ifdef HS_FEAT_ICAP
++ "icap",
++#endif
+ "TOTAL"
+ };
+
+@@ -217,6 +220,10 @@ urlParseProtocol(const char *s)
+ return PROTO_WHOIS;
+ if (strcasecmp(s, "internal") == 0)
+ return PROTO_INTERNAL;
++#ifdef HS_FEAT_ICAP
++ if (strcasecmp(s, "icap") == 0)
++ return PROTO_ICAP;
++#endif
+ return PROTO_NONE;
+ }
+
+@@ -240,6 +247,10 @@ urlDefaultPort(protocol_t p)
+ return CACHE_HTTP_PORT;
+ case PROTO_WHOIS:
+ return 43;
++#ifdef HS_FEAT_ICAP
++ case PROTO_ICAP:
++ return 1344;
++#endif
+ default:
+ return 0;
+ }
diff --git a/www/squid26/files/patch-changeset.10801 b/www/squid26/files/patch-changeset.10801
deleted file mode 100644
index f73e5dbf7b4d..000000000000
--- a/www/squid26/files/patch-changeset.10801
+++ /dev/null
@@ -1,284 +0,0 @@
----------------------
-PatchSet 10801
-Date: 2006/07/04 21:51:15
-Author: hno
-Branch: HEAD
-Tag: (none)
-Log:
-Bug #1650: transparent interception "Unable to forward this request at this time"
-
-this patch clears up some confusion between accelerated and transparently
-intercepted requests, clearly separating the two cases.
-
-With this patch the --enable-auth-on-acceleration is removed again as it
-no longer serves any purpose as there no longer is any conflict between
-the processing accelerated and transparently intercepted requests.
-
-Members:
- configure:1.388->1.389
- configure.in:1.384->1.385
- include/autoconf.h.in:1.153->1.154
- src/acl.c:1.303->1.304
- src/client_side.c:1.657->1.658
- src/structs.h:1.489->1.490
-
-Index: squid/configure
-===================================================================
-RCS file: /cvsroot/squid/squid/configure,v
-retrieving revision 1.388
-retrieving revision 1.389
-diff -u -r1.388 -r1.389
---- configure 1 Jul 2006 18:42:04 -0000 1.388
-+++ configure 4 Jul 2006 21:51:15 -0000 1.389
-@@ -907,8 +907,6 @@
- --enable-forw-via-db Enable Forw/Via database
- --enable-cache-digests Use Cache Digests
- see http://www.squid-cache.org/FAQ/FAQ-16.html
-- --enable-auth-on-acceleration
-- Enable authentication in accelerators
- --enable-default-err-language=lang
- Select default language for Error pages (see
- errors directory)
-@@ -4220,20 +4218,6 @@
-
- fi;
-
--# Check whether --enable-auth-on-acceleration or --disable-auth-on-acceleration was given.
--if test "${enable_auth_on_acceleration+set}" = set; then
-- enableval="$enable_auth_on_acceleration"
-- if test "$enableval" = "yes" ; then
-- echo "AUTH_ON_ACCELERATION enabled"
--
--cat >>confdefs.h <<\_ACEOF
--#define AUTH_ON_ACCELERATION 1
--_ACEOF
--
-- fi
--
--fi;
--
- # Check whether --enable-default-err-language or --disable-default-err-language was given.
- if test "${enable_default_err_language+set}" = set; then
- enableval="$enable_default_err_language"
-Index: squid/configure.in
-===================================================================
-RCS file: /cvsroot/squid/squid/configure.in,v
-retrieving revision 1.384
-retrieving revision 1.385
-diff -u -r1.384 -r1.385
---- configure.in 1 Jul 2006 18:41:21 -0000 1.384
-+++ configure.in 4 Jul 2006 21:51:15 -0000 1.385
-@@ -736,15 +736,6 @@
- fi
- ])
-
--AC_ARG_ENABLE(auth-on-acceleration,
--[ --enable-auth-on-acceleration
-- Enable authentication in accelerators],
--[ if test "$enableval" = "yes" ; then
-- echo "AUTH_ON_ACCELERATION enabled"
-- AC_DEFINE(AUTH_ON_ACCELERATION, 1, [Enable authentication support in accelerators])
-- fi
--])
--
- dnl Select Default Error language
- AC_ARG_ENABLE(default-err-language,
- [ --enable-default-err-language=lang
-Index: squid/include/autoconf.h.in
-===================================================================
-RCS file: /cvsroot/squid/squid/include/autoconf.h.in,v
-retrieving revision 1.153
-retrieving revision 1.154
-diff -u -r1.153 -r1.154
---- include/autoconf.h.in 21 Jun 2006 20:33:46 -0000 1.153
-+++ include/autoconf.h.in 4 Jul 2006 21:51:16 -0000 1.154
-@@ -3,9 +3,6 @@
- /* Defines how many threads aufs uses for I/O */
- #undef AUFS_IO_THREADS
-
--/* Enable authentication support in accelerators */
--#undef AUTH_ON_ACCELERATION
--
- /* If you are upset that the cachemgr.cgi form comes up with the hostname
- field blank, then define this to getfullhostname() */
- #undef CACHEMGR_HOSTNAME
-Index: squid/src/acl.c
-===================================================================
-RCS file: /cvsroot/squid/squid/src/acl.c,v
-retrieving revision 1.303
-retrieving revision 1.304
-diff -u -r1.303 -r1.304
---- src/acl.c 17 Jun 2006 23:31:03 -0000 1.303
-+++ src/acl.c 4 Jul 2006 21:51:16 -0000 1.304
-@@ -400,6 +400,10 @@
- type->accelerated = 1;
- continue;
- }
-+ if (strcmp(t, "transparent") == 0) {
-+ type->transparent = 1;
-+ continue;
-+ }
- if (strcmp(t, "internal") == 0) {
- type->internal = 1;
- continue;
-@@ -1679,6 +1683,8 @@
- {
- if (type->accelerated && request->flags.accelerated)
- return 1;
-+ if (type->transparent && request->flags.transparent)
-+ return 1;
- if (type->internal && request->flags.internal)
- return 1;
- return 0;
-@@ -1691,20 +1697,15 @@
- http_hdr_type headertype;
- if (NULL == r) {
- return -1;
-- } else if (!r->flags.accelerated) {
-- /* Proxy authorization on proxy requests */
-- headertype = HDR_PROXY_AUTHORIZATION;
-- } else if (r->flags.internal) {
-- /* WWW authorization on accelerated internal requests */
-- headertype = HDR_AUTHORIZATION;
-- } else {
--#if AUTH_ON_ACCELERATION
-+ } else if (r->flags.accelerated) {
- /* WWW authorization on accelerated requests */
- headertype = HDR_AUTHORIZATION;
--#else
-- debug(28, 1) ("aclAuthenticated: authentication not applicable on accelerated requests.\n");
-+ } else if (r->flags.transparent) {
-+ debug(28, 1) ("aclAuthenticated: authentication not applicable on transparently intercepted requests.\n");
- return -1;
--#endif
-+ } else {
-+ /* Proxy authorization on proxy requests */
-+ headertype = HDR_PROXY_AUTHORIZATION;
- }
- /* get authed here */
- /* Note: this fills in checklist->auth_user_request when applicable (auth incomplete) */
-@@ -2911,6 +2912,8 @@
- wordlistAdd(&W, "accelerated");
- if (type->internal)
- wordlistAdd(&W, "internal");
-+ if (type->transparent)
-+ wordlistAdd(&W, "transparent");
- return W;
- }
-
-Index: squid/src/client_side.c
-===================================================================
-RCS file: /cvsroot/squid/squid/src/client_side.c,v
-retrieving revision 1.657
-retrieving revision 1.658
-diff -u -r1.657 -r1.658
---- src/client_side.c 4 Jul 2006 00:06:11 -0000 1.657
-+++ src/client_side.c 4 Jul 2006 21:51:17 -0000 1.658
-@@ -3482,7 +3482,7 @@
- /*
- * Deny loops when running in accelerator/transproxy mode.
- */
-- if (http->flags.accel && r->flags.loopdetect) {
-+ if (r->flags.loopdetect && (http->flags.accel || http->flags.transparent)) {
- http->al.http.code = HTTP_FORBIDDEN;
- err = errorCon(ERR_ACCESS_DENIED, HTTP_FORBIDDEN);
- err->request = requestLink(http->orig_request);
-@@ -3684,15 +3684,19 @@
- if (method == METHOD_CONNECT) {
- if (http_ver.major < 1)
- goto invalid_request;
-+ if (conn->port->accel)
-+ goto invalid_request;
- } else if (*url == '/')
- accel:{
- int vhost = conn->port->vhost || conn->port->transparent;
-- int vport = conn->port->vport || conn->transparent;
-+ int vport = conn->port->vport;
-+ int accel = conn->port->accel;
-+ if (!vport && conn->transparent)
-+ vport = ntohs(conn->me.sin_port);
- if (Config.onoff.global_internal_static && conn->port->accel && internalCheck(url)) {
- /* prepend our name & port */
- http->uri = xstrdup(internalStoreUri("", url));
- http->flags.internal = 1;
-- http->flags.accel = 1;
- debug(33, 5) ("INTERNAL REWRITE: '%s'\n", http->uri);
- } else if (vhost && (t = mime_get_header(req_hdr, "Host"))) {
- url_sz = strlen(url) + 32 + Config.appendDomainLen +
-@@ -3724,14 +3728,14 @@
- /* prepend our name & port */
- http->uri = xstrdup(internalStoreUri("", url));
- http->flags.internal = 1;
-- http->flags.accel = 1;
- debug(33, 5) ("INTERNAL REWRITE: '%s'\n", http->uri);
- } else {
- goto invalid_request;
- }
-- http->flags.accel = 1;
-- } else if (conn->transparent) {
-- http->flags.accel = 1;
-+ if (accel)
-+ http->flags.accel = 1;
-+ else if (conn->port->transparent)
-+ http->flags.transparent = 1;
- } else if (conn->port->accel) {
- http->flags.accel = 1;
- if (!conn->port->vhost) {
-@@ -3743,9 +3747,6 @@
- url = (char *) "/";
- goto accel;
- }
-- } else {
-- /* Proxy request */
-- http->flags.accel = 0;
- }
- if (!http->uri) {
- /* No special rewrites have been applied above, use the
-@@ -3753,7 +3754,6 @@
- url_sz = strlen(url) + Config.appendDomainLen + 5;
- http->uri = xcalloc(url_sz, 1);
- strcpy(http->uri, url);
-- http->flags.accel = 0;
- }
- if (!stringHasCntl(http->uri))
- http->log_uri = xstrndup(http->uri, MAX_URL);
-@@ -3989,6 +3989,7 @@
- request->flags.tproxy = conn->port->tproxy;
- #endif
- request->flags.accelerated = http->flags.accel;
-+ request->flags.transparent = http->flags.transparent;
- /*
- * cache the Content-length value in request_t.
- */
-Index: squid/src/structs.h
-===================================================================
-RCS file: /cvsroot/squid/squid/src/structs.h,v
-retrieving revision 1.489
-retrieving revision 1.490
-diff -u -r1.489 -r1.490
---- src/structs.h 30 Jun 2006 21:23:05 -0000 1.489
-+++ src/structs.h 4 Jul 2006 21:51:18 -0000 1.490
-@@ -346,6 +346,7 @@
-
- struct _acl_request_type {
- unsigned int accelerated:1;
-+ unsigned int transparent:1;
- unsigned int internal:1;
- };
-
-@@ -1190,6 +1191,7 @@
- AccessLogEntry al;
- struct {
- unsigned int accel:1;
-+ unsigned int transparent:1;
- unsigned int internal:1;
- unsigned int done_copying:1;
- unsigned int purging:1;
-@@ -1785,6 +1787,7 @@
- unsigned int nocache_hack:1; /* for changing/ignoring no-cache requests */
- #endif
- unsigned int accelerated:1;
-+ unsigned int transparent:1;
- unsigned int internal:1;
- unsigned int body_sent:1;
- unsigned int reset_tcp:1;
diff --git a/www/squid26/files/patch-src-client_side.c b/www/squid26/files/patch-src-client_side.c
deleted file mode 100644
index 3c9eed63c572..000000000000
--- a/www/squid26/files/patch-src-client_side.c
+++ /dev/null
@@ -1,16 +0,0 @@
---- ./src/client_side.c.orig Thu Jul 6 11:44:18 2006
-+++ ./src/client_side.c Thu Jul 6 11:52:07 2006
-@@ -4490,6 +4490,13 @@
- return -1;
- }
- }
-+#elif IPFW_TRANSPARENT
-+static int inline
-+clientNatLookup(ConnStateData * conn)
-+{
-+ static time_t last_reported = 0;
-+ return 0;
-+}
- #else
- static int inline
- clientNatLookup(ConnStateData * conn)
diff --git a/www/squid27/Makefile b/www/squid27/Makefile
index 54f8810d1153..284fc896064b 100644
--- a/www/squid27/Makefile
+++ b/www/squid27/Makefile
@@ -75,8 +75,7 @@
# Enable experimental multicast notification of cachemisses.
PORTNAME= squid
-PORTVERSION= 2.6.1
-PORTREVISION= 1
+PORTVERSION= 2.6.2
CATEGORIES= www
MASTER_SITES= ftp://ftp.squid-cache.org/pub/%SUBDIR%/ \
ftp://archive.progeny.com/squid/%SUBDIR%/ \
@@ -88,7 +87,7 @@ MASTER_SITES= ftp://ftp.squid-cache.org/pub/%SUBDIR%/ \
ftp://ftp.ccs.neu.edu/pub/mirrors/squid.nlanr.net/pub/%SUBDIR%/ \
${MASTER_SITE_RINGSERVER:S,%SUBDIR%,net/www/squid/&,}
MASTER_SITE_SUBDIR= squid-2/STABLE
-DISTNAME= squid-2.6.STABLE1
+DISTNAME= squid-2.6.STABLE2
DIST_SUBDIR= squid2.6
PATCH_SITES= http://www.squid-cache.org/%SUBDIR%/ \
@@ -101,7 +100,8 @@ PATCH_SITES= http://www.squid-cache.org/%SUBDIR%/ \
http://www1.jp.squid-cache.org/%SUBDIR%/ \
http://www1.tw.squid-cache.org/%SUBDIR%/
PATCH_SITE_SUBDIR= Versions/v2/2.6/changesets/
-PATCHFILES= 10799.patch
+PATCHFILES= 10894.patch 10895.patch 10896.patch 10898.patch 10899.patch \
+ 10900.patch 10901.patch 10902.patch 10903.patch 10904.patch
PATCH_DIST_STRIP= -p1
MAINTAINER= tmseck@netcologne.de
@@ -144,7 +144,6 @@ OPTIONS= SQUID_LDAP_AUTH "Install LDAP authentication helpers" off \
SQUID_ARP_ACL "Enable ACLs based on ethernet address" off \
SQUID_PF "Enable transparent proxying with PF" off \
SQUID_IPFILTER "Enable transp. proxying with IPFilter" off \
- SQUID_IPFW "Enable transparent proxying with IPFW" off \
SQUID_FOLLOW_XFF "Follow X-Forwarded-For headers" off \
SQUID_ICAP "Enable ICAP client functionality" off \
SQUID_AUFS "Enable the aufs storage scheme" off \
@@ -187,7 +186,7 @@ libexec= cachemgr.cgi digest_pw_auth diskd-daemon ip_user_check \
libexec+= unlinkd
.endif
-sbin= RunCache squidclient squid
+sbin= RunCache cossdump squidclient squid
CONFIGURE_ARGS= --bindir=${PREFIX}/sbin \
--sbindir=${PREFIX}/sbin \
@@ -331,17 +330,14 @@ IGNORE= IPFilter headers are not part of the base system
CONFIGURE_ARGS+= --enable-ipf-transparent
.endif
.endif
-.if defined(WITH_SQUID_IPFW)
-CFLAGS+= -DIPFW_TRANSPARENT
-.endif
.if defined(WITH_SQUID_FOLLOW_XFF)
CONFIGURE_ARGS+= --enable-follow-x-forwarded-for
.endif
.if defined(WITH_SQUID_ICAP)
-IGNORE= patches for ICAP support are not yet updated
-EXTRA_PATCHES+=
-#CONFIGURE_ARGS+= --enable-icap-support
-#error_files+= ERR_ICAP_FAILURE
+EXTRA_PATCHES+= ${PATCHDIR}/icap-2.6-bootstrap.patch \
+ ${PATCHDIR}/icap-2.6-core.patch
+CONFIGURE_ARGS+= --enable-icap-support
+error_files+= ERR_ICAP_FAILURE
.endif
.if !defined(WITHOUT_SQUID_KQUEUE)
CONFIGURE_ARGS+= --enable-kqueue
diff --git a/www/squid27/distinfo b/www/squid27/distinfo
index 1d11150734c3..f4b602d9732d 100644
--- a/www/squid27/distinfo
+++ b/www/squid27/distinfo
@@ -1,6 +1,33 @@
-MD5 (squid2.6/squid-2.6.STABLE1.tar.bz2) = d6bb23a67b0475cca11d4af8d574d054
-SHA256 (squid2.6/squid-2.6.STABLE1.tar.bz2) = a9efea26f1c3966dff69f80c271a73562afed5c65929d69dab713308dd402ba9
-SIZE (squid2.6/squid-2.6.STABLE1.tar.bz2) = 1212556
-MD5 (squid2.6/10799.patch) = 3a3d941b0d256a1da9ad8f2430da4e2b
-SHA256 (squid2.6/10799.patch) = 0f010962faae226a21761996df7c487ed6ca2d51458e6941a9f2a5b69aa3e6c3
-SIZE (squid2.6/10799.patch) = 1288
+MD5 (squid2.6/squid-2.6.STABLE2.tar.bz2) = 838492f95de0964e31e633bfa07a0682
+SHA256 (squid2.6/squid-2.6.STABLE2.tar.bz2) = 8ceb890161648f26b3c16f07e2e1beecad2b0de0f3f1793142a32b5aa25ef8e6
+SIZE (squid2.6/squid-2.6.STABLE2.tar.bz2) = 1222355
+MD5 (squid2.6/10894.patch) = 8b66b5f16a1563e15690f0b8ecddd5b9
+SHA256 (squid2.6/10894.patch) = cab38b13352135433fb85e04a76182ca96b03e4c6df487b6de25e73b1bf71ffd
+SIZE (squid2.6/10894.patch) = 1303
+MD5 (squid2.6/10895.patch) = 234efdec5f31662d07188829bcd28721
+SHA256 (squid2.6/10895.patch) = 8d12a761c64ca9b8c7f18e4393f47d22e4bd772a788bcbea61c81f48647a8835
+SIZE (squid2.6/10895.patch) = 5885
+MD5 (squid2.6/10896.patch) = 187944a1b8b3e796f5ae5d18b2d66284
+SHA256 (squid2.6/10896.patch) = 0a8d6dd65a3d9d76b9aeb85135f560abe9a53ce17891e866d0e38f14aa4f436b
+SIZE (squid2.6/10896.patch) = 1100
+MD5 (squid2.6/10898.patch) = 830d6788b613b93221d7661bf19946a1
+SHA256 (squid2.6/10898.patch) = f6b95725ba7d78fdbd41a8589229acf9b2128deb109adbe13d5f7e0d81d192f7
+SIZE (squid2.6/10898.patch) = 3611
+MD5 (squid2.6/10899.patch) = dee2d52860f2ee66bb4ecbfbdbf1f66f
+SHA256 (squid2.6/10899.patch) = c3c8b334fe5d6f3e5037e6db4cf6e5049076e07e44df2f5cd8f0f4a9d0fde5fd
+SIZE (squid2.6/10899.patch) = 1641
+MD5 (squid2.6/10900.patch) = 5bb888d3a4041572bc38f9cf6e177e5e
+SHA256 (squid2.6/10900.patch) = 48bc152e1986efb4ef58b64409d062b1a01a09cba0c4dcb31b719bb595c11751
+SIZE (squid2.6/10900.patch) = 917
+MD5 (squid2.6/10901.patch) = 16d5d2bf91a868da672daa8c24f0ca74
+SHA256 (squid2.6/10901.patch) = f0fe03966617b895e1fae361e8aa8557a51433c1c4eec92599424f0d2ece545e
+SIZE (squid2.6/10901.patch) = 1709
+MD5 (squid2.6/10902.patch) = f9b7dd81b26a17e52175d06161b00ee6
+SHA256 (squid2.6/10902.patch) = d63c4dca13096ce3185ad6b15de2f897f24018581a69e611e9a00dbf5842ab59
+SIZE (squid2.6/10902.patch) = 1439
+MD5 (squid2.6/10903.patch) = 008c0c4e8b08def33f48f2706d13433e
+SHA256 (squid2.6/10903.patch) = 727dbe9951d915f7b846ed905148ce4177703dbbfa493d45b5efbb1da61851e0
+SIZE (squid2.6/10903.patch) = 968
+MD5 (squid2.6/10904.patch) = 20d803cd8ede1132d8f8009cc93ca816
+SHA256 (squid2.6/10904.patch) = 36bf8c00084988a850bcbe816cf52a7002e8516806fb7a17438eaeeb389457fa
+SIZE (squid2.6/10904.patch) = 37791
diff --git a/www/squid27/files/icap-2.6-bootstrap.patch b/www/squid27/files/icap-2.6-bootstrap.patch
new file mode 100644
index 000000000000..548a7e97ac89
--- /dev/null
+++ b/www/squid27/files/icap-2.6-bootstrap.patch
@@ -0,0 +1,473 @@
+Patch 2 of 2 to integrate the icap-2_6 branch into the FreeBSD squid port.
+
+Created by Thomas-Martin Seck <tmseck@netcologne.de>.
+
+This patch simulates the autotools bootstrap necessary after applying the
+ICAP patchset.
+
+Please see icap-2.6-core.patch for further information.
+
+Patch last updated: 2006-08-05
+
+--- configure.orig Sat Aug 5 16:24:35 2006
++++ configure Sat Aug 5 16:19:46 2006
+@@ -270,8 +270,8 @@
+ # Identity of this package.
+ PACKAGE_NAME='Squid Web Proxy'
+ PACKAGE_TARNAME='squid'
+-PACKAGE_VERSION='2.6.STABLE2'
+-PACKAGE_STRING='Squid Web Proxy 2.6.STABLE2'
++PACKAGE_VERSION='2.6.STABLE2-CVS'
++PACKAGE_STRING='Squid Web Proxy 2.6.STABLE2-CVS'
+ PACKAGE_BUGREPORT='http://www.squid-cache.org/bugs/'
+
+ ac_default_prefix=/usr/local/squid
+@@ -312,7 +312,7 @@
+ # include <unistd.h>
+ #endif"
+
+-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE build build_cpu build_vendor build_os host host_cpu host_vendor host_os PKGCONFIG CGIEXT ENABLE_WIN32SPECIFIC_TRUE ENABLE_WIN32SPECIFIC_FALSE CACHE_HTTP_PORT CACHE_ICP_PORT LIBDLMALLOC LIB_MALLOC STORE_OBJS STORE_LIBS STORE_MODULES NEED_DISKD_TRUE NEED_DISKD_FALSE REPL_POLICIES REPL_OBJS REPL_LIBS ENABLE_PINGER_TRUE ENABLE_PINGER_FALSE USE_DELAY_POOLS_TRUE USE_DELAY_POOLS_FALSE USE_SNMP_TRUE USE_SNMP_FALSE SNMPLIB makesnmplib ENABLE_HTCP_TRUE ENABLE_HTCP_FALSE ENABLE_SSL_TRUE ENABLE_SSL_FALSE NEED_OWN_MD5_TRUE NEED_OWN_MD5_FALSE SSLLIB ERR_DEFAULT_LANGUAGE ERR_LANGUAGES MAKE_LEAKFINDER_TRUE MAKE_LEAKFINDER_FALSE USE_DNSSERVER_TRUE USE_DNSSERVER_FALSE OPT_DEFAULT_HOSTS AUTH_MODULES AUTH_OBJS AUTH_LIBS BASIC_AUTH_HELPERS NTLM_AUTH_HELPERS DIGEST_AUTH_HELPERS NEGOTIATE_AUTH_HELPERS EXTERNAL_ACL_HELPERS CPP EGREP LIBSASL ENABLE_UNLINKD_TRUE ENABLE_UNLINKD_FALSE RANLIB ac_ct_RANLIB LN_S SH FALSE TRUE RM MV MKDIR LN PERL AR AR_R ALLOCA CRYPTLIB LIB_EPOLL LIB_LDAP LIB_LBER LIB_DB EPOLL_LIBS USE_POLL_TRUE USE_POLL_FALSE USE_EPOLL_TRUE USE_EPOLL_FALSE USE_SELECT_TRUE USE_SELECT_FALSE USE_SELECT_WIN32_TRUE USE_SELECT_WIN32_FALSE USE_KQUEUE_TRUE USE_KQUEUE_FALSE NEED_OWN_SNPRINTF_TRUE NEED_OWN_SNPRINTF_FALSE NEED_OWN_STRSEP_TRUE NEED_OWN_STRSEP_FALSE REGEXLIB LIBREGEX LIBOBJS XTRA_OBJS XTRA_LIBS LTLIBOBJS'
++ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE build build_cpu build_vendor build_os host host_cpu host_vendor host_os PKGCONFIG CGIEXT ENABLE_WIN32SPECIFIC_TRUE ENABLE_WIN32SPECIFIC_FALSE CACHE_HTTP_PORT CACHE_ICP_PORT LIBDLMALLOC LIB_MALLOC STORE_OBJS STORE_LIBS STORE_MODULES NEED_DISKD_TRUE NEED_DISKD_FALSE REPL_POLICIES REPL_OBJS REPL_LIBS ENABLE_PINGER_TRUE ENABLE_PINGER_FALSE USE_DELAY_POOLS_TRUE USE_DELAY_POOLS_FALSE USE_ICAP_TRUE USE_ICAP_FALSE USE_SNMP_TRUE USE_SNMP_FALSE SNMPLIB makesnmplib ENABLE_HTCP_TRUE ENABLE_HTCP_FALSE ENABLE_SSL_TRUE ENABLE_SSL_FALSE NEED_OWN_MD5_TRUE NEED_OWN_MD5_FALSE SSLLIB ERR_DEFAULT_LANGUAGE ERR_LANGUAGES MAKE_LEAKFINDER_TRUE MAKE_LEAKFINDER_FALSE USE_DNSSERVER_TRUE USE_DNSSERVER_FALSE OPT_DEFAULT_HOSTS AUTH_MODULES AUTH_OBJS AUTH_LIBS BASIC_AUTH_HELPERS NTLM_AUTH_HELPERS DIGEST_AUTH_HELPERS NEGOTIATE_AUTH_HELPERS EXTERNAL_ACL_HELPERS CPP EGREP LIBSASL ENABLE_UNLINKD_TRUE ENABLE_UNLINKD_FALSE RANLIB ac_ct_RANLIB LN_S SH FALSE TRUE RM MV MKDIR LN PERL AR AR_R ALLOCA CRYPTLIB LIB_EPOLL LIB_LDAP LIB_LBER LIB_DB EPOLL_LIBS USE_POLL_TRUE USE_POLL_FALSE USE_EPOLL_TRUE USE_EPOLL_FALSE USE_SELECT_TRUE USE_SELECT_FALSE USE_SELECT_WIN32_TRUE USE_SELECT_WIN32_FALSE USE_KQUEUE_TRUE USE_KQUEUE_FALSE NEED_OWN_SNPRINTF_TRUE NEED_OWN_SNPRINTF_FALSE NEED_OWN_STRNSTR_TRUE NEED_OWN_STRNSTR_FALSE NEED_OWN_STRCASESTR_TRUE NEED_OWN_STRCASESTR_FALSE NEED_OWN_STRSEP_TRUE NEED_OWN_STRSEP_FALSE REGEXLIB LIBREGEX LIBOBJS XTRA_OBJS XTRA_LIBS LTLIBOBJS'
+ ac_subst_files=''
+
+ # Initialize some variables set by options.
+@@ -890,6 +890,7 @@
+ to build your custom policy
+ --enable-icmp Enable ICMP pinging
+ --enable-delay-pools Enable delay pools to limit bandwidth usage
++ --enable-icap-support Enable ICAP client capability
+ --enable-useragent-log Enable logging of User-Agent header
+ --enable-referer-log Enable logging of Referer header
+ --disable-wccp Disable Web Cache Coordination V1 Protocol
+@@ -3843,6 +3844,40 @@
+ fi;
+
+
++
++if false; then
++ USE_ICAP_TRUE=
++ USE_ICAP_FALSE='#'
++else
++ USE_ICAP_TRUE='#'
++ USE_ICAP_FALSE=
++fi
++
++# Check whether --enable-icap-support or --disable-icap-support was given.
++if test "${enable_icap_support+set}" = set; then
++ enableval="$enable_icap_support"
++ if test "$enableval" = "yes" ; then
++ echo "ICAP support enabled"
++
++cat >>confdefs.h <<\_ACEOF
++#define HS_FEAT_ICAP 1
++_ACEOF
++
++
++
++if true; then
++ USE_ICAP_TRUE=
++ USE_ICAP_FALSE='#'
++else
++ USE_ICAP_TRUE='#'
++ USE_ICAP_FALSE=
++fi
++
++ fi
++
++fi;
++
++
+ # Check whether --enable-useragent-log or --disable-useragent-log was given.
+ if test "${enable_useragent_log+set}" = set; then
+ enableval="$enable_useragent_log"
+@@ -15688,6 +15725,8 @@
+ srand48 \
+ srandom \
+ statfs \
++ strnstr \
++ strcasestr \
+ strsep \
+ strtoll \
+ sysconf \
+@@ -16247,6 +16286,52 @@
+
+
+ if false; then
++ NEED_OWN_STRNSTR_TRUE=
++ NEED_OWN_STRNSTR_FALSE='#'
++else
++ NEED_OWN_STRNSTR_TRUE='#'
++ NEED_OWN_STRNSTR_FALSE=
++fi
++
++if test "$ac_cv_func_strnstr" = "no" || test "$ac_cv_func_vstrnstr" = "no" ; then
++
++
++if true; then
++ NEED_OWN_STRNSTR_TRUE=
++ NEED_OWN_STRNSTR_FALSE='#'
++else
++ NEED_OWN_STRNSTR_TRUE='#'
++ NEED_OWN_STRNSTR_FALSE=
++fi
++
++fi
++
++
++
++if false; then
++ NEED_OWN_STRCASESTR_TRUE=
++ NEED_OWN_STRCASESTR_FALSE='#'
++else
++ NEED_OWN_STRCASESTR_TRUE='#'
++ NEED_OWN_STRCASESTR_FALSE=
++fi
++
++if test "$ac_cv_func_strcasestr" = "no" || test "$ac_cv_func_vstrcasestr" = "no"; then
++
++
++if true; then
++ NEED_OWN_STRCASESTR_TRUE=
++ NEED_OWN_STRCASESTR_FALSE='#'
++else
++ NEED_OWN_STRCASESTR_TRUE='#'
++ NEED_OWN_STRCASESTR_FALSE=
++fi
++
++fi
++
++
++
++if false; then
+ NEED_OWN_STRSEP_TRUE=
+ NEED_OWN_STRSEP_FALSE='#'
+ else
+@@ -17731,6 +17816,20 @@
+ Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
++if test -z "${USE_ICAP_TRUE}" && test -z "${USE_ICAP_FALSE}"; then
++ { { echo "$as_me:$LINENO: error: conditional \"USE_ICAP\" was never defined.
++Usually this means the macro was only invoked conditionally." >&5
++echo "$as_me: error: conditional \"USE_ICAP\" was never defined.
++Usually this means the macro was only invoked conditionally." >&2;}
++ { (exit 1); exit 1; }; }
++fi
++if test -z "${USE_ICAP_TRUE}" && test -z "${USE_ICAP_FALSE}"; then
++ { { echo "$as_me:$LINENO: error: conditional \"USE_ICAP\" was never defined.
++Usually this means the macro was only invoked conditionally." >&5
++echo "$as_me: error: conditional \"USE_ICAP\" was never defined.
++Usually this means the macro was only invoked conditionally." >&2;}
++ { (exit 1); exit 1; }; }
++fi
+ if test -z "${USE_SNMP_TRUE}" && test -z "${USE_SNMP_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"USE_SNMP\" was never defined.
+ Usually this means the macro was only invoked conditionally." >&5
+@@ -17878,6 +17977,34 @@
+ Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
++if test -z "${NEED_OWN_STRNSTR_TRUE}" && test -z "${NEED_OWN_STRNSTR_FALSE}"; then
++ { { echo "$as_me:$LINENO: error: conditional \"NEED_OWN_STRNSTR\" was never defined.
++Usually this means the macro was only invoked conditionally." >&5
++echo "$as_me: error: conditional \"NEED_OWN_STRNSTR\" was never defined.
++Usually this means the macro was only invoked conditionally." >&2;}
++ { (exit 1); exit 1; }; }
++fi
++if test -z "${NEED_OWN_STRNSTR_TRUE}" && test -z "${NEED_OWN_STRNSTR_FALSE}"; then
++ { { echo "$as_me:$LINENO: error: conditional \"NEED_OWN_STRNSTR\" was never defined.
++Usually this means the macro was only invoked conditionally." >&5
++echo "$as_me: error: conditional \"NEED_OWN_STRNSTR\" was never defined.
++Usually this means the macro was only invoked conditionally." >&2;}
++ { (exit 1); exit 1; }; }
++fi
++if test -z "${NEED_OWN_STRCASESTR_TRUE}" && test -z "${NEED_OWN_STRCASESTR_FALSE}"; then
++ { { echo "$as_me:$LINENO: error: conditional \"NEED_OWN_STRCASESTR\" was never defined.
++Usually this means the macro was only invoked conditionally." >&5
++echo "$as_me: error: conditional \"NEED_OWN_STRCASESTR\" was never defined.
++Usually this means the macro was only invoked conditionally." >&2;}
++ { (exit 1); exit 1; }; }
++fi
++if test -z "${NEED_OWN_STRCASESTR_TRUE}" && test -z "${NEED_OWN_STRCASESTR_FALSE}"; then
++ { { echo "$as_me:$LINENO: error: conditional \"NEED_OWN_STRCASESTR\" was never defined.
++Usually this means the macro was only invoked conditionally." >&5
++echo "$as_me: error: conditional \"NEED_OWN_STRCASESTR\" was never defined.
++Usually this means the macro was only invoked conditionally." >&2;}
++ { (exit 1); exit 1; }; }
++fi
+ if test -z "${NEED_OWN_STRSEP_TRUE}" && test -z "${NEED_OWN_STRSEP_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"NEED_OWN_STRSEP\" was never defined.
+ Usually this means the macro was only invoked conditionally." >&5
+@@ -18536,6 +18663,8 @@
+ s,@ENABLE_PINGER_FALSE@,$ENABLE_PINGER_FALSE,;t t
+ s,@USE_DELAY_POOLS_TRUE@,$USE_DELAY_POOLS_TRUE,;t t
+ s,@USE_DELAY_POOLS_FALSE@,$USE_DELAY_POOLS_FALSE,;t t
++s,@USE_ICAP_TRUE@,$USE_ICAP_TRUE,;t t
++s,@USE_ICAP_FALSE@,$USE_ICAP_FALSE,;t t
+ s,@USE_SNMP_TRUE@,$USE_SNMP_TRUE,;t t
+ s,@USE_SNMP_FALSE@,$USE_SNMP_FALSE,;t t
+ s,@SNMPLIB@,$SNMPLIB,;t t
+@@ -18599,6 +18728,10 @@
+ s,@USE_KQUEUE_FALSE@,$USE_KQUEUE_FALSE,;t t
+ s,@NEED_OWN_SNPRINTF_TRUE@,$NEED_OWN_SNPRINTF_TRUE,;t t
+ s,@NEED_OWN_SNPRINTF_FALSE@,$NEED_OWN_SNPRINTF_FALSE,;t t
++s,@NEED_OWN_STRNSTR_TRUE@,$NEED_OWN_STRNSTR_TRUE,;t t
++s,@NEED_OWN_STRNSTR_FALSE@,$NEED_OWN_STRNSTR_FALSE,;t t
++s,@NEED_OWN_STRCASESTR_TRUE@,$NEED_OWN_STRCASESTR_TRUE,;t t
++s,@NEED_OWN_STRCASESTR_FALSE@,$NEED_OWN_STRCASESTR_FALSE,;t t
+ s,@NEED_OWN_STRSEP_TRUE@,$NEED_OWN_STRSEP_TRUE,;t t
+ s,@NEED_OWN_STRSEP_FALSE@,$NEED_OWN_STRSEP_FALSE,;t t
+ s,@REGEXLIB@,$REGEXLIB,;t t
+--- include/autoconf.h.in.orig Wed Jul 12 17:00:31 2006
++++ include/autoconf.h.in Sat Aug 5 16:18:25 2006
+@@ -454,6 +454,9 @@
+ /* Define to 1 if you have the <stdlib.h> header file. */
+ #undef HAVE_STDLIB_H
+
++/* Define to 1 if you have the `strcasestr' function. */
++#undef HAVE_STRCASESTR
++
+ /* Define to 1 if you have the `strerror' function. */
+ #undef HAVE_STRERROR
+
+@@ -463,6 +466,9 @@
+ /* Define to 1 if you have the <string.h> header file. */
+ #undef HAVE_STRING_H
+
++/* Define to 1 if you have the `strnstr' function. */
++#undef HAVE_STRNSTR
++
+ /* Define to 1 if you have the `strsep' function. */
+ #undef HAVE_STRSEP
+
+@@ -587,6 +593,9 @@
+
+ /* Some systems support __va_copy */
+ #undef HAVE___VA_COPY
++
++/* Content filtering via ICAP servers. */
++#undef HS_FEAT_ICAP
+
+ /* By default (for now anyway) Squid includes options which allows the cache
+ administrator to violate the HTTP protocol specification in terms of cache
+--- lib/Makefile.in.orig Mon Jun 12 08:10:08 2006
++++ lib/Makefile.in Sat Aug 5 16:19:17 2006
+@@ -62,18 +62,21 @@
+ am__libmiscutil_a_SOURCES_DIST = Array.c base64.c getfullhostname.c \
+ hash.c heap.c html_quote.c iso3307.c md5.c radix.c rfc1035.c \
+ rfc1123.c rfc1738.c rfc2617.c safe_inet_addr.c snprintf.c \
+- splay.c Stack.c strsep.c stub_memaccount.c util.c uudecode.c
++ splay.c Stack.c strnstr.c strcasestr.c strsep.c \
++ stub_memaccount.c util.c uudecode.c
+ @NEED_OWN_MD5_TRUE@am__objects_1 = md5.$(OBJEXT)
+ @NEED_OWN_SNPRINTF_TRUE@am__objects_2 = snprintf.$(OBJEXT)
+-@NEED_OWN_STRSEP_TRUE@am__objects_3 = strsep.$(OBJEXT)
++@NEED_OWN_STRNSTR_TRUE@am__objects_3 = strnstr.$(OBJEXT)
++@NEED_OWN_STRCASESTR_TRUE@am__objects_4 = strcasestr.$(OBJEXT)
++@NEED_OWN_STRSEP_TRUE@am__objects_5 = strsep.$(OBJEXT)
+ am_libmiscutil_a_OBJECTS = Array.$(OBJEXT) base64.$(OBJEXT) \
+ getfullhostname.$(OBJEXT) hash.$(OBJEXT) heap.$(OBJEXT) \
+ html_quote.$(OBJEXT) iso3307.$(OBJEXT) $(am__objects_1) \
+ radix.$(OBJEXT) rfc1035.$(OBJEXT) rfc1123.$(OBJEXT) \
+ rfc1738.$(OBJEXT) rfc2617.$(OBJEXT) safe_inet_addr.$(OBJEXT) \
+ $(am__objects_2) splay.$(OBJEXT) Stack.$(OBJEXT) \
+- $(am__objects_3) stub_memaccount.$(OBJEXT) util.$(OBJEXT) \
+- uudecode.$(OBJEXT)
++ $(am__objects_3) $(am__objects_4) $(am__objects_5) \
++ stub_memaccount.$(OBJEXT) util.$(OBJEXT) uudecode.$(OBJEXT)
+ libmiscutil_a_OBJECTS = $(am_libmiscutil_a_OBJECTS)
+ libntlmauth_a_AR = $(AR) $(ARFLAGS)
+ libntlmauth_a_DEPENDENCIES = @LIBOBJS@
+@@ -184,6 +187,10 @@
+ NEED_OWN_MD5_TRUE = @NEED_OWN_MD5_TRUE@
+ NEED_OWN_SNPRINTF_FALSE = @NEED_OWN_SNPRINTF_FALSE@
+ NEED_OWN_SNPRINTF_TRUE = @NEED_OWN_SNPRINTF_TRUE@
++NEED_OWN_STRCASESTR_FALSE = @NEED_OWN_STRCASESTR_FALSE@
++NEED_OWN_STRCASESTR_TRUE = @NEED_OWN_STRCASESTR_TRUE@
++NEED_OWN_STRNSTR_FALSE = @NEED_OWN_STRNSTR_FALSE@
++NEED_OWN_STRNSTR_TRUE = @NEED_OWN_STRNSTR_TRUE@
+ NEED_OWN_STRSEP_FALSE = @NEED_OWN_STRSEP_FALSE@
+ NEED_OWN_STRSEP_TRUE = @NEED_OWN_STRSEP_TRUE@
+ NEGOTIATE_AUTH_HELPERS = @NEGOTIATE_AUTH_HELPERS@
+@@ -221,6 +228,8 @@
+ USE_DNSSERVER_TRUE = @USE_DNSSERVER_TRUE@
+ USE_EPOLL_FALSE = @USE_EPOLL_FALSE@
+ USE_EPOLL_TRUE = @USE_EPOLL_TRUE@
++USE_ICAP_FALSE = @USE_ICAP_FALSE@
++USE_ICAP_TRUE = @USE_ICAP_TRUE@
+ USE_KQUEUE_FALSE = @USE_KQUEUE_FALSE@
+ USE_KQUEUE_TRUE = @USE_KQUEUE_TRUE@
+ USE_POLL_FALSE = @USE_POLL_FALSE@
+@@ -275,6 +284,10 @@
+ target_alias = @target_alias@
+ @NEED_OWN_SNPRINTF_FALSE@SNPRINTFSOURCE =
+ @NEED_OWN_SNPRINTF_TRUE@SNPRINTFSOURCE = snprintf.c
++@NEED_OWN_STRNSTR_FALSE@STRNSTRSOURCE =
++@NEED_OWN_STRNSTR_TRUE@STRNSTRSOURCE = strnstr.c
++@NEED_OWN_STRCASESTR_FALSE@STRCASESTRSOURCE =
++@NEED_OWN_STRCASESTR_TRUE@STRCASESTRSOURCE = strcasestr.c
+ @NEED_OWN_STRSEP_FALSE@STRSEPSOURCE =
+ @NEED_OWN_STRSEP_TRUE@STRSEPSOURCE = strsep.c
+ @NEED_OWN_MD5_FALSE@MD5SOURCE =
+@@ -316,6 +329,8 @@
+ $(SNPRINTFSOURCE) \
+ splay.c \
+ Stack.c \
++ $(STRNSTRSOURCE) \
++ $(STRCASESTRSOURCE) \
+ $(STRSEPSOURCE) \
+ stub_memaccount.c \
+ util.c \
+@@ -430,6 +445,8 @@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snprintf.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/splay.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sspwin32.Po@am__quote@
++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strcasestr.Po@am__quote@
++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strnstr.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strsep.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stub_memaccount.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@
+--- src/Makefile.in.orig Sun Jul 30 10:56:18 2006
++++ src/Makefile.in Sat Aug 5 16:19:21 2006
+@@ -90,18 +90,20 @@
+ forward.c fqdncache.c ftp.c globals.h gopher.c helper.c htcp.c \
+ http.c HttpStatusLine.c HttpHdrCc.c HttpHdrRange.c \
+ HttpHdrContRange.c HttpHeader.c HttpHeaderTools.c HttpBody.c \
+- HttpMsg.c HttpReply.c HttpRequest.c icmp.c icp_v2.c icp_v3.c \
+- ident.c internal.c ipc.c ipcache.c leakfinder.c locrewrite.c \
+- logfile.c main.c mem.c MemPool.c MemBuf.c mime.c multicast.c \
+- neighbors.c net_db.c Packer.c pconn.c peer_digest.c \
+- peer_monitor.c peer_select.c peer_sourcehash.c peer_userhash.c \
+- protos.h redirect.c referer.c refresh.c send-announce.c \
+- snmp_core.c snmp_agent.c squid.h ssl.c ssl_support.c stat.c \
+- StatHist.c String.c stmem.c store.c store_io.c store_client.c \
+- store_digest.c store_dir.c store_key_md5.c store_log.c \
+- store_rebuild.c store_swapin.c store_swapmeta.c \
+- store_swapout.c structs.h tools.c typedefs.h unlinkd.c url.c \
+- urn.c useragent.c wais.c wccp.c wccp2.c whois.c win32.c
++ HttpMsg.c HttpReply.c HttpRequest.c icap_common.c \
++ icap_reqmod.c icap_respmod.c icap_opt.c icmp.c icp_v2.c \
++ icp_v3.c ident.c internal.c ipc.c ipcache.c leakfinder.c \
++ locrewrite.c logfile.c main.c mem.c MemPool.c MemBuf.c mime.c \
++ multicast.c neighbors.c net_db.c Packer.c pconn.c \
++ peer_digest.c peer_monitor.c peer_select.c peer_sourcehash.c \
++ peer_userhash.c protos.h redirect.c referer.c refresh.c \
++ send-announce.c snmp_core.c snmp_agent.c squid.h ssl.c \
++ ssl_support.c stat.c StatHist.c String.c stmem.c store.c \
++ store_io.c store_client.c store_digest.c store_dir.c \
++ store_key_md5.c store_log.c store_rebuild.c store_swapin.c \
++ store_swapmeta.c store_swapout.c structs.h tools.c typedefs.h \
++ unlinkd.c url.c urn.c useragent.c wais.c wccp.c wccp2.c \
++ whois.c win32.c
+ @USE_EPOLL_FALSE@@USE_KQUEUE_FALSE@@USE_POLL_FALSE@@USE_SELECT_FALSE@@USE_SELECT_WIN32_TRUE@am__objects_1 = comm_select_win32.$(OBJEXT)
+ @USE_EPOLL_FALSE@@USE_KQUEUE_FALSE@@USE_POLL_FALSE@@USE_SELECT_TRUE@am__objects_1 = comm_select.$(OBJEXT)
+ @USE_EPOLL_FALSE@@USE_KQUEUE_FALSE@@USE_POLL_TRUE@am__objects_1 = comm_poll.$(OBJEXT)
+@@ -112,12 +114,15 @@
+ @USE_DNSSERVER_FALSE@am__objects_3 = dns_internal.$(OBJEXT)
+ @USE_DNSSERVER_TRUE@am__objects_3 = dns.$(OBJEXT)
+ @ENABLE_HTCP_TRUE@am__objects_4 = htcp.$(OBJEXT)
+-@MAKE_LEAKFINDER_TRUE@am__objects_5 = leakfinder.$(OBJEXT)
+-@USE_SNMP_TRUE@am__objects_6 = snmp_core.$(OBJEXT) \
++@USE_ICAP_TRUE@am__objects_5 = icap_common.$(OBJEXT) \
++@USE_ICAP_TRUE@ icap_reqmod.$(OBJEXT) icap_respmod.$(OBJEXT) \
++@USE_ICAP_TRUE@ icap_opt.$(OBJEXT)
++@MAKE_LEAKFINDER_TRUE@am__objects_6 = leakfinder.$(OBJEXT)
++@USE_SNMP_TRUE@am__objects_7 = snmp_core.$(OBJEXT) \
+ @USE_SNMP_TRUE@ snmp_agent.$(OBJEXT)
+-@ENABLE_SSL_TRUE@am__objects_7 = ssl_support.$(OBJEXT)
+-@ENABLE_UNLINKD_TRUE@am__objects_8 = unlinkd.$(OBJEXT)
+-@ENABLE_WIN32SPECIFIC_TRUE@am__objects_9 = win32.$(OBJEXT)
++@ENABLE_SSL_TRUE@am__objects_8 = ssl_support.$(OBJEXT)
++@ENABLE_UNLINKD_TRUE@am__objects_9 = unlinkd.$(OBJEXT)
++@ENABLE_WIN32SPECIFIC_TRUE@am__objects_10 = win32.$(OBJEXT)
+ am_squid_OBJECTS = access_log.$(OBJEXT) acl.$(OBJEXT) asn.$(OBJEXT) \
+ authenticate.$(OBJEXT) cache_cf.$(OBJEXT) \
+ CacheDigest.$(OBJEXT) cache_manager.$(OBJEXT) carp.$(OBJEXT) \
+@@ -132,27 +137,27 @@
+ HttpHdrRange.$(OBJEXT) HttpHdrContRange.$(OBJEXT) \
+ HttpHeader.$(OBJEXT) HttpHeaderTools.$(OBJEXT) \
+ HttpBody.$(OBJEXT) HttpMsg.$(OBJEXT) HttpReply.$(OBJEXT) \
+- HttpRequest.$(OBJEXT) icmp.$(OBJEXT) icp_v2.$(OBJEXT) \
+- icp_v3.$(OBJEXT) ident.$(OBJEXT) internal.$(OBJEXT) \
+- ipc.$(OBJEXT) ipcache.$(OBJEXT) $(am__objects_5) \
+- locrewrite.$(OBJEXT) logfile.$(OBJEXT) main.$(OBJEXT) \
+- mem.$(OBJEXT) MemPool.$(OBJEXT) MemBuf.$(OBJEXT) \
+- mime.$(OBJEXT) multicast.$(OBJEXT) neighbors.$(OBJEXT) \
+- net_db.$(OBJEXT) Packer.$(OBJEXT) pconn.$(OBJEXT) \
+- peer_digest.$(OBJEXT) peer_monitor.$(OBJEXT) \
++ HttpRequest.$(OBJEXT) $(am__objects_5) icmp.$(OBJEXT) \
++ icp_v2.$(OBJEXT) icp_v3.$(OBJEXT) ident.$(OBJEXT) \
++ internal.$(OBJEXT) ipc.$(OBJEXT) ipcache.$(OBJEXT) \
++ $(am__objects_6) locrewrite.$(OBJEXT) logfile.$(OBJEXT) \
++ main.$(OBJEXT) mem.$(OBJEXT) MemPool.$(OBJEXT) \
++ MemBuf.$(OBJEXT) mime.$(OBJEXT) multicast.$(OBJEXT) \
++ neighbors.$(OBJEXT) net_db.$(OBJEXT) Packer.$(OBJEXT) \
++ pconn.$(OBJEXT) peer_digest.$(OBJEXT) peer_monitor.$(OBJEXT) \
+ peer_select.$(OBJEXT) peer_sourcehash.$(OBJEXT) \
+ peer_userhash.$(OBJEXT) redirect.$(OBJEXT) referer.$(OBJEXT) \
+- refresh.$(OBJEXT) send-announce.$(OBJEXT) $(am__objects_6) \
+- ssl.$(OBJEXT) $(am__objects_7) stat.$(OBJEXT) \
++ refresh.$(OBJEXT) send-announce.$(OBJEXT) $(am__objects_7) \
++ ssl.$(OBJEXT) $(am__objects_8) stat.$(OBJEXT) \
+ StatHist.$(OBJEXT) String.$(OBJEXT) stmem.$(OBJEXT) \
+ store.$(OBJEXT) store_io.$(OBJEXT) store_client.$(OBJEXT) \
+ store_digest.$(OBJEXT) store_dir.$(OBJEXT) \
+ store_key_md5.$(OBJEXT) store_log.$(OBJEXT) \
+ store_rebuild.$(OBJEXT) store_swapin.$(OBJEXT) \
+ store_swapmeta.$(OBJEXT) store_swapout.$(OBJEXT) \
+- tools.$(OBJEXT) $(am__objects_8) url.$(OBJEXT) urn.$(OBJEXT) \
++ tools.$(OBJEXT) $(am__objects_9) url.$(OBJEXT) urn.$(OBJEXT) \
+ useragent.$(OBJEXT) wais.$(OBJEXT) wccp.$(OBJEXT) \
+- wccp2.$(OBJEXT) whois.$(OBJEXT) $(am__objects_9)
++ wccp2.$(OBJEXT) whois.$(OBJEXT) $(am__objects_10)
+ nodist_squid_OBJECTS = repl_modules.$(OBJEXT) auth_modules.$(OBJEXT) \
+ store_modules.$(OBJEXT) globals.$(OBJEXT) \
+ string_arrays.$(OBJEXT)
+@@ -274,6 +279,10 @@
+ NEED_OWN_MD5_TRUE = @NEED_OWN_MD5_TRUE@
+ NEED_OWN_SNPRINTF_FALSE = @NEED_OWN_SNPRINTF_FALSE@
+ NEED_OWN_SNPRINTF_TRUE = @NEED_OWN_SNPRINTF_TRUE@
++NEED_OWN_STRCASESTR_FALSE = @NEED_OWN_STRCASESTR_FALSE@
++NEED_OWN_STRCASESTR_TRUE = @NEED_OWN_STRCASESTR_TRUE@
++NEED_OWN_STRNSTR_FALSE = @NEED_OWN_STRNSTR_FALSE@
++NEED_OWN_STRNSTR_TRUE = @NEED_OWN_STRNSTR_TRUE@
+ NEED_OWN_STRSEP_FALSE = @NEED_OWN_STRSEP_FALSE@
+ NEED_OWN_STRSEP_TRUE = @NEED_OWN_STRSEP_TRUE@
+ NEGOTIATE_AUTH_HELPERS = @NEGOTIATE_AUTH_HELPERS@
+@@ -311,6 +320,8 @@
+ USE_DNSSERVER_TRUE = @USE_DNSSERVER_TRUE@
+ USE_EPOLL_FALSE = @USE_EPOLL_FALSE@
+ USE_EPOLL_TRUE = @USE_EPOLL_TRUE@
++USE_ICAP_FALSE = @USE_ICAP_FALSE@
++USE_ICAP_TRUE = @USE_ICAP_TRUE@
+ USE_KQUEUE_FALSE = @USE_KQUEUE_FALSE@
+ USE_KQUEUE_TRUE = @USE_KQUEUE_TRUE@
+ USE_POLL_FALSE = @USE_POLL_FALSE@
+@@ -363,6 +374,8 @@
+ sharedstatedir = @sharedstatedir@
+ sysconfdir = @sysconfdir@
+ target_alias = @target_alias@
++@USE_ICAP_FALSE@ICAPSOURCE =
++@USE_ICAP_TRUE@ICAPSOURCE = icap_common.c icap_reqmod.c icap_respmod.c icap_opt.c
+ @USE_DNSSERVER_FALSE@DNSSOURCE = dns_internal.c
+ @USE_DNSSERVER_TRUE@DNSSOURCE = dns.c
+ @USE_DNSSERVER_FALSE@DNSSERVER =
+@@ -458,6 +471,7 @@
+ HttpMsg.c \
+ HttpReply.c \
+ HttpRequest.c \
++ $(ICAPSOURCE) \
+ icmp.c \
+ icp_v2.c \
+ icp_v3.c \
+@@ -768,6 +782,10 @@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/helper.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htcp.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http.Po@am__quote@
++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/icap_common.Po@am__quote@
++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/icap_opt.Po@am__quote@
++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/icap_reqmod.Po@am__quote@
++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/icap_respmod.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/icmp.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/icp_v2.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/icp_v3.Po@am__quote@
diff --git a/www/squid27/files/icap-2.6-core.patch b/www/squid27/files/icap-2.6-core.patch
new file mode 100644
index 000000000000..64af138a69db
--- /dev/null
+++ b/www/squid27/files/icap-2.6-core.patch
@@ -0,0 +1,7159 @@
+Patch 1 of 2 to integrate the icap-2_6 branch into the FreeBSD squid port.
+
+Created by Thomas-Martin Seck <tmseck@netcologne.de>.
+
+This patch only contains the parts of the original patchset that
+actually implement the ICAP client functionality. The updates to
+the build infrastructure are omitted to avoid the need to run an
+autotools bootstrap. Instead, we simulate said bootstrapping with
+a second patch, icap-2.6-bootstrap.patch.
+
+The patchset was pulled from the project's CVS repository
+at cvs.devel.squid-cache.org using
+
+cvs diff -u -b -N -kk -rZ-icap-s2_6_merge_HEAD -ricap-2_6
+
+See http://devel.squid-cache.org/icap/ for further information
+about the ICAP client project.
+
+Patch last updated: 2006-08-05
+
+Index: errors/Azerbaijani/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Azerbaijani/ERR_ICAP_FAILURE
+diff -N errors/Azerbaijani/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Azerbaijani/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Bulgarian/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Bulgarian/ERR_ICAP_FAILURE
+diff -N errors/Bulgarian/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Bulgarian/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Catalan/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Catalan/ERR_ICAP_FAILURE
+diff -N errors/Catalan/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Catalan/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Czech/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Czech/ERR_ICAP_FAILURE
+diff -N errors/Czech/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Czech/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Danish/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Danish/ERR_ICAP_FAILURE
+diff -N errors/Danish/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Danish/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Dutch/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Dutch/ERR_ICAP_FAILURE
+diff -N errors/Dutch/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Dutch/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/English/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/English/ERR_ICAP_FAILURE
+diff -N errors/English/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/English/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Estonian/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Estonian/ERR_ICAP_FAILURE
+diff -N errors/Estonian/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Estonian/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Finnish/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Finnish/ERR_ICAP_FAILURE
+diff -N errors/Finnish/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Finnish/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/French/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/French/ERR_ICAP_FAILURE
+diff -N errors/French/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/French/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/German/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/German/ERR_ICAP_FAILURE
+diff -N errors/German/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/German/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.14.1
+@@ -0,0 +1,33 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>FEHLER: Der angeforderte URL konnte nicht geholt werden</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>FEHLER</H1>
++<H2>Der angeforderte URL konnte nicht geholt werden</H2>
++<HR noshade size="1px">
++<P>
++W&auml;hrend des Versuches, den URL<BR>
++<A HREF="%U">%U</A>
++
++<BR>
++zu laden, trat der folgende Fehler auf:
++<UL>
++<LI>
++<STRONG>
++ICAP-Protokollfehler
++</STRONG>
++</UL>
++
++<P>
++<P>
++Es trat ein Problem bei der ICAP-Kommunikation auf. M&ouml;gliche Gr&uuml;nde:
++<UL>
++<LI>Nicht erreichbarer ICAP-Server
++<LI>Ung&uuml;ltige Antwort vom ICAP-Server
++
++</UL>
++</P>
++
++<P>Ihr Cache Administrator ist <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Greek/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Greek/ERR_ICAP_FAILURE
+diff -N errors/Greek/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Greek/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.12.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Hebrew/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Hebrew/ERR_ICAP_FAILURE
+diff -N errors/Hebrew/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Hebrew/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Hungarian/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Hungarian/ERR_ICAP_FAILURE
+diff -N errors/Hungarian/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Hungarian/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Italian/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Italian/ERR_ICAP_FAILURE
+diff -N errors/Italian/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Italian/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Japanese/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Japanese/ERR_ICAP_FAILURE
+diff -N errors/Japanese/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Japanese/ERR_ICAP_FAILURE 17 May 2006 17:57:59 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Korean/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Korean/ERR_ICAP_FAILURE
+diff -N errors/Korean/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Korean/ERR_ICAP_FAILURE 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Lithuanian/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Lithuanian/ERR_ICAP_FAILURE
+diff -N errors/Lithuanian/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Lithuanian/ERR_ICAP_FAILURE 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Polish/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Polish/ERR_ICAP_FAILURE
+diff -N errors/Polish/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Polish/ERR_ICAP_FAILURE 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Portuguese/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Portuguese/ERR_ICAP_FAILURE
+diff -N errors/Portuguese/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Portuguese/ERR_ICAP_FAILURE 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Romanian/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Romanian/ERR_ICAP_FAILURE
+diff -N errors/Romanian/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Romanian/ERR_ICAP_FAILURE 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Russian-1251/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Russian-1251/ERR_ICAP_FAILURE
+diff -N errors/Russian-1251/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Russian-1251/ERR_ICAP_FAILURE 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Russian-koi8-r/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Russian-koi8-r/ERR_ICAP_FAILURE
+diff -N errors/Russian-koi8-r/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Russian-koi8-r/ERR_ICAP_FAILURE 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Serbian/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Serbian/ERR_ICAP_FAILURE
+diff -N errors/Serbian/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Serbian/ERR_ICAP_FAILURE 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Simplify_Chinese/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Simplify_Chinese/ERR_ICAP_FAILURE
+diff -N errors/Simplify_Chinese/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Simplify_Chinese/ERR_ICAP_FAILURE 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Slovak/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Slovak/ERR_ICAP_FAILURE
+diff -N errors/Slovak/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Slovak/ERR_ICAP_FAILURE 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Spanish/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Spanish/ERR_ICAP_FAILURE
+diff -N errors/Spanish/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Spanish/ERR_ICAP_FAILURE 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Swedish/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Swedish/ERR_ICAP_FAILURE
+diff -N errors/Swedish/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Swedish/ERR_ICAP_FAILURE 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Traditional_Chinese/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Traditional_Chinese/ERR_ICAP_FAILURE
+diff -N errors/Traditional_Chinese/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Traditional_Chinese/ERR_ICAP_FAILURE 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: errors/Turkish/ERR_ICAP_FAILURE
+===================================================================
+RCS file: errors/Turkish/ERR_ICAP_FAILURE
+diff -N errors/Turkish/ERR_ICAP_FAILURE
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ errors/Turkish/ERR_ICAP_FAILURE 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,31 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
++<HTML><HEAD>
++<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
++<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
++</HEAD><BODY>
++<H1>ERROR</H1>
++<H2>The requested URL could not be retrieved</H2>
++<HR noshade size="1px">
++<P>
++While attempting to retrieve the URL:
++<A HREF="%U">%U</A>
++<P>
++the following error was encountered:
++<UL>
++<LI>
++<STRONG>
++ICAP protocol error.
++</STRONG>
++</UL>
++
++<P>
++<P>
++Some aspect of the ICAP communication failed. Possible problems:
++<UL>
++<LI>ICAP server is not reachable.
++<LI>Illegal response from ICAP server.
++</UL>
++</P>
++
++<P>Your cache administrator is <A HREF="mailto:%w">%w</A>.
++
+Index: include/util.h
+===================================================================
+RCS file: /cvsroot/squid/squid/include/util.h,v
+retrieving revision 1.13
+retrieving revision 1.13.8.1
+diff -p -u -b -r1.13 -r1.13.8.1
+--- include/util.h 12 May 2006 22:51:56 -0000 1.13
++++ include/util.h 17 May 2006 17:58:00 -0000 1.13.8.1
+@@ -123,4 +123,12 @@ double drand48(void);
+ */
+ int statMemoryAccounted(void);
+
++#ifndef HAVE_STRNSTR
++extern char *strnstr(const char *haystack, const char *needle, size_t haystacklen);
++#endif
++
++#ifndef HAVE_STRCASESTR
++extern char *strcasestr(const char *haystack, const char *needle);
++#endif
++
+ #endif /* SQUID_UTIL_H */
+Index: lib/strcasestr.c
+===================================================================
+RCS file: lib/strcasestr.c
+diff -N lib/strcasestr.c
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ lib/strcasestr.c 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,126 @@
++/* Return the offset of one string within another.
++ Copyright (C) 1994,1996,1997,1998,1999,2000 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library 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
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++/*
++ * My personal strstr() implementation that beats most other algorithms.
++ * Until someone tells me otherwise, I assume that this is the
++ * fastest implementation of strstr() in C.
++ * I deliberately chose not to comment it. You should have at least
++ * as much fun trying to understand it, as I had to write it :-).
++ *
++ * Stephen R. van den Berg, berg@pool.informatik.rwth-aachen.de */
++
++/*
++ * modified to work outside of glibc (rhorstmann, 06/04/2004)
++ */
++
++#include "config.h"
++#ifndef HAVE_STRCASESTR
++#include <ctype.h>
++
++typedef unsigned chartype;
++
++char *
++strcasestr (phaystack, pneedle)
++ const char *phaystack;
++ const char *pneedle;
++{
++ register const unsigned char *haystack, *needle;
++ register chartype b, c;
++
++ haystack = (const unsigned char *) phaystack;
++ needle = (const unsigned char *) pneedle;
++
++ b = tolower (*needle);
++ if (b != '\0')
++ {
++ haystack--; /* possible ANSI violation */
++ do
++ {
++ c = *++haystack;
++ if (c == '\0')
++ goto ret0;
++ }
++ while (tolower (c) != (int) b);
++
++ c = tolower (*++needle);
++ if (c == '\0')
++ goto foundneedle;
++ ++needle;
++ goto jin;
++
++ for (;;)
++ {
++ register chartype a;
++ register const unsigned char *rhaystack, *rneedle;
++
++ do
++ {
++ a = *++haystack;
++ if (a == '\0')
++ goto ret0;
++ if (tolower (a) == (int) b)
++ break;
++ a = *++haystack;
++ if (a == '\0')
++ goto ret0;
++shloop:
++ ;
++ }
++ while (tolower (a) != (int) b);
++
++jin: a = *++haystack;
++ if (a == '\0')
++ goto ret0;
++
++ if (tolower (a) != (int) c)
++ goto shloop;
++
++ rhaystack = haystack-- + 1;
++ rneedle = needle;
++ a = tolower (*rneedle);
++
++ if (tolower (*rhaystack) == (int) a)
++ do
++ {
++ if (a == '\0')
++ goto foundneedle;
++ ++rhaystack;
++ a = tolower (*++needle);
++ if (tolower (*rhaystack) != (int) a)
++ break;
++ if (a == '\0')
++ goto foundneedle;
++ ++rhaystack;
++ a = tolower (*++needle);
++ }
++ while (tolower (*rhaystack) == (int) a);
++
++ needle = rneedle; /* took the register-poor approach */
++
++ if (a == '\0')
++ break;
++ }
++ }
++foundneedle:
++ return (char*) haystack;
++ret0:
++ return 0;
++}
++#endif
+Index: lib/strnstr.c
+===================================================================
+RCS file: lib/strnstr.c
+diff -N lib/strnstr.c
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ lib/strnstr.c 17 May 2006 17:58:00 -0000 1.1.14.1
+@@ -0,0 +1,52 @@
++/*
++ * Copyright (C) 2003 Nikos Mavroyanopoulos
++ *
++ * This file is part of GNUTLS.
++ *
++ * The GNUTLS library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++
++ /*
++ * DW 2003/10/17:
++ * Changed 'ssize_t' types to 'size_t'
++ */
++
++#include "config.h"
++#ifndef HAVE_STRNSTR
++#include <string.h>
++#include <util.h>
++
++char *strnstr(const char *haystack, const char *needle, size_t haystacklen)
++{
++ char *p;
++ size_t plen;
++ size_t len = strlen(needle);
++
++ if (*needle == '\0') /* everything matches empty string */
++ return (char*) haystack;
++
++ plen = haystacklen;
++ for (p = (char*) haystack; p != NULL; p = memchr(p + 1, *needle, plen-1)) {
++ plen = haystacklen - (p - haystack);
++
++ if (plen < len) return NULL;
++
++ if (strncmp(p, needle, len) == 0)
++ return (p);
++ }
++ return NULL;
++}
++#endif
+Index: src/MemBuf.c
+===================================================================
+RCS file: /cvsroot/squid/squid/src/MemBuf.c,v
+retrieving revision 1.10
+retrieving revision 1.9.10.2
+diff -p -u -b -r1.10 -r1.9.10.2
+--- src/MemBuf.c 20 May 2006 22:50:55 -0000 1.10
++++ src/MemBuf.c 26 May 2006 18:21:31 -0000 1.9.10.2
+@@ -341,3 +341,15 @@ memBufReport(MemBuf * mb)
+ assert(mb);
+ memBufPrintf(mb, "memBufReport is not yet implemented @?@\n");
+ }
++
++int
++memBufRead(int fd, MemBuf * mb)
++{
++ int len;
++ if (mb->capacity == mb->size)
++ memBufGrow(mb, SQUID_TCP_SO_RCVBUF);
++ len = FD_READ_METHOD(fd, mb->buf + mb->size, mb->capacity - mb->size);
++ if (len)
++ mb->size += len;
++ return len;
++}
+Index: src/cache_cf.c
+===================================================================
+RCS file: /cvsroot/squid/squid/src/cache_cf.c,v
+retrieving revision 1.80
+retrieving revision 1.61.4.8
+diff -p -u -b -r1.80 -r1.61.4.8
+--- src/cache_cf.c 30 Jul 2006 23:52:54 -0000 1.80
++++ src/cache_cf.c 3 Aug 2006 17:16:01 -0000 1.61.4.8
+@@ -2367,6 +2367,587 @@ check_null_body_size_t(dlink_list bodyli
+ return bodylist.head == NULL;
+ }
+
++#ifdef HS_FEAT_ICAP
++
++/***************************************************
++ * prototypes
++ */
++static int icap_service_process(icap_service * s);
++static void icap_service_init(icap_service * s);
++static void icap_service_destroy(icap_service * s);
++icap_service *icap_service_lookup(char *name);
++static int icap_class_process(icap_class * c);
++static void icap_class_destroy(icap_class * c);
++static void icap_access_destroy(icap_access * a);
++static void dump_wordlist(StoreEntry * entry, const char *name, const wordlist * list);
++static void icap_class_add(icap_class * c);
++
++/***************************************************
++ * icap_service
++ */
++
++/*
++ * example:
++ * icap_service reqmode_precache 0 icap://192.168.0.1:1344/respmod
++ */
++
++static void
++parse_icap_service_type(IcapConfig * cfg)
++{
++ char *token;
++ icap_service *A = NULL;
++ icap_service *B = NULL;
++ icap_service **T = NULL;
++
++ A = cbdataAlloc(icap_service);
++ icap_service_init(A);
++ parse_string(&A->name);
++ parse_string(&A->type_name);
++ parse_ushort(&A->bypass);
++ parse_string(&A->uri);
++ while ((token = strtok(NULL, w_space))) {
++ if (strcasecmp(token, "no-keep-alive") == 0) {
++ A->keep_alive = 0;
++ } else {
++ debug(3, 0) ("parse_peer: token='%s'\n", token);
++ self_destruct();
++ }
++ }
++ debug(3, 5) ("parse_icap_service_type (line %d): %s %s %d %s\n", config_lineno, A->name, A->type_name, A->bypass, A->name);
++ if (icap_service_process(A)) {
++ /* put into linked list */
++ for (B = cfg->service_head, T = &cfg->service_head; B; T = &B->next, B = B->next);
++ *T = A;
++ } else {
++ /* clean up structure */
++ debug(3, 0) ("parse_icap_service_type (line %d): skipping %s\n", config_lineno, A->name);
++ icap_service_destroy(A);
++ cbdataFree(A);
++ }
++
++}
++
++static void
++dump_icap_service_type(StoreEntry * e, const char *name, IcapConfig cfg)
++{
++ icap_service *current_node = NULL;
++
++ if (!cfg.service_head) {
++ storeAppendPrintf(e, "%s 0\n", name);
++ return;
++ }
++ current_node = cfg.service_head;
++
++ while (current_node) {
++ storeAppendPrintf(e, "%s %s %s %d %s", name, current_node->name, current_node->type_name, current_node->bypass, current_node->uri);
++ if (current_node->keep_alive == 0) {
++ storeAppendPrintf(e, " no-keep-alive");
++ }
++ storeAppendPrintf(e, "\n");
++ current_node = current_node->next;
++ }
++
++}
++
++static void
++free_icap_service_type(IcapConfig * cfg)
++{
++ while (cfg->service_head) {
++ icap_service *current_node = cfg->service_head;
++ cfg->service_head = current_node->next;
++ icap_service_destroy(current_node);
++ cbdataFree(current_node);
++ }
++}
++
++/*
++ * parse the raw string and cache some parts that are needed later
++ * returns 1 if everything was ok
++ */
++static int
++icap_service_process(icap_service * s)
++{
++ char *start, *end, *tempEnd;
++ char *tailp;
++ unsigned int len;
++ int port_in_uri, resource_in_uri = 0;
++ s->type = icapServiceToType(s->type_name);
++ if (s->type >= ICAP_SERVICE_MAX) {
++ debug(3, 0) ("icap_service_process (line %d): wrong service type %s\n", config_lineno, s->type_name);
++ return 0;
++ }
++ if (s->type == ICAP_SERVICE_REQMOD_PRECACHE)
++ s->method = ICAP_METHOD_REQMOD;
++ else if (s->type == ICAP_SERVICE_REQMOD_PRECACHE)
++ s->method = ICAP_METHOD_REQMOD;
++ else if (s->type == ICAP_SERVICE_REQMOD_POSTCACHE)
++ s->method = ICAP_METHOD_REQMOD;
++ else if (s->type == ICAP_SERVICE_RESPMOD_PRECACHE)
++ s->method = ICAP_METHOD_RESPMOD;
++ else if (s->type == ICAP_SERVICE_RESPMOD_POSTCACHE)
++ s->method = ICAP_METHOD_RESPMOD;
++ debug(3, 5) ("icap_service_process (line %d): type=%s\n", config_lineno, icapServiceToStr(s->type));
++ if (strncmp(s->uri, "icap://", 7) != 0) {
++ debug(3, 0) ("icap_service_process (line %d): wrong uri: %s\n", config_lineno, s->uri);
++ return 0;
++ }
++ start = s->uri + 7;
++ if ((end = strchr(start, ':')) != NULL) {
++ /* ok */
++ port_in_uri = 1;
++ debug(3, 5) ("icap_service_process (line %d): port given\n", config_lineno);
++ } else {
++ /* ok */
++ port_in_uri = 0;
++ debug(3, 5) ("icap_service_process (line %d): no port given\n", config_lineno);
++ }
++
++ if ((tempEnd = strchr(start, '/')) != NULL) {
++ /* ok */
++ resource_in_uri = 1;
++ debug(3, 5) ("icap_service_process (line %d): resource given\n", config_lineno);
++ if (end == '\0') {
++ end = tempEnd;
++ }
++ } else {
++ /* ok */
++ resource_in_uri = 0;
++ debug(3, 5) ("icap_service_process (line %d): no resource given\n", config_lineno);
++ }
++
++ tempEnd = strchr(start, '\0');
++ if (end == '\0') {
++ end = tempEnd;
++ }
++ len = end - start;
++ s->hostname = xstrndup(start, len + 1);
++ s->hostname[len] = 0;
++ debug(3, 5) ("icap_service_process (line %d): hostname=%s\n", config_lineno, s->hostname);
++ start = end;
++
++ if (port_in_uri) {
++ start++; /* skip ':' */
++ if (resource_in_uri)
++ end = strchr(start, '/');
++ else
++ end = strchr(start, '\0');
++ s->port = strtoul(start, &tailp, 0) % 65536;
++ if (tailp != end) {
++ debug(3, 0) ("icap_service_process (line %d): wrong service uri (port could not be parsed): %s\n", config_lineno, s->uri);
++ return 0;
++ }
++ debug(3, 5) ("icap_service_process (line %d): port=%d\n", config_lineno, s->port);
++ start = end;
++ } else {
++ /* no explicit ICAP port; first ask by getservbyname or default to
++ * hardwired port 1344 per ICAP specification section 4.2 */
++ struct servent *serv = getservbyname("icap", "tcp");
++ if (serv) {
++ s->port = htons(serv->s_port);
++ debug(3, 5) ("icap_service_process (line %d): default port=%d getservbyname(icap,tcp)\n", config_lineno, s->port);
++ } else {
++ s->port = 1344;
++ debug(3, 5) ("icap_service_process (line %d): default hardwired port=%d\n", config_lineno, s->port);
++ }
++ }
++
++ if (resource_in_uri) {
++ start++; /* skip '/' */
++ /* the rest is resource name */
++ end = strchr(start, '\0');
++ len = end - start;
++ if (len > 1024) {
++ debug(3, 0) ("icap_service_process (line %d): long resource name (>1024), probably wrong\n", config_lineno);
++ }
++ s->resource = xstrndup(start, len + 1);
++ s->resource[len] = 0;
++ debug(3, 5) ("icap_service_process (line %d): service=%s\n", config_lineno, s->resource);
++ }
++ /* check bypass */
++ if ((s->bypass != 0) && (s->bypass != 1)) {
++ debug(3, 0) ("icap_service_process (line %d): invalid bypass value\n", config_lineno);
++ return 0;
++ }
++ return 1;
++}
++
++/*
++ * constructor
++ */
++static void
++icap_service_init(icap_service * s)
++{
++ s->type = ICAP_SERVICE_MAX; /* means undefined */
++ s->preview = Config.icapcfg.preview_size;
++ s->opt = 0;
++ s->keep_alive = 1;
++ s->istag = StringNull;
++ s->transfer_preview = StringNull;
++ s->transfer_ignore = StringNull;
++ s->transfer_complete = StringNull;
++}
++
++/*
++ * destructor
++ * frees only strings, but don't touch the linked list
++ */
++static void
++icap_service_destroy(icap_service * s)
++{
++ xfree(s->name);
++ xfree(s->uri);
++ xfree(s->type_name);
++ xfree(s->hostname);
++ xfree(s->resource);
++ assert(s->opt == 0); /* there should be no opt request running now */
++ stringClean(&s->istag);
++ stringClean(&s->transfer_preview);
++ stringClean(&s->transfer_ignore);
++ stringClean(&s->transfer_complete);
++}
++
++icap_service *
++icap_service_lookup(char *name)
++{
++ icap_service *iter;
++ for (iter = Config.icapcfg.service_head; iter; iter = iter->next) {
++ if (!strcmp(name, iter->name)) {
++ return iter;
++ }
++ }
++ return NULL;
++}
++
++/***************************************************
++ * icap_service_list
++ */
++
++static void
++icap_service_list_add(icap_service_list ** isl, char *service_name)
++{
++ icap_service_list **iter;
++ icap_service_list *new;
++ icap_service *gbl_service;
++ int i;
++ int max_services;
++
++ new = memAllocate(MEM_ICAP_SERVICE_LIST);
++ /* Found all services with that name, and add to the array */
++ max_services = sizeof(new->services) / sizeof(icap_service *);
++ gbl_service = Config.icapcfg.service_head;
++ i = 0;
++ while (gbl_service && i < max_services) {
++ if (!strcmp(service_name, gbl_service->name))
++ new->services[i++] = gbl_service;
++ gbl_service = gbl_service->next;
++ }
++ new->nservices = i;
++
++ if (*isl) {
++ iter = isl;
++ while ((*iter)->next)
++ iter = &((*iter)->next);
++ (*iter)->next = new;
++ } else {
++ *isl = new;
++ }
++}
++
++/*
++ * free the linked list without touching references icap_service
++ */
++static void
++icap_service_list_destroy(icap_service_list * isl)
++{
++ icap_service_list *current;
++ icap_service_list *next;
++
++ current = isl;
++ while (current) {
++ next = current->next;
++ memFree(current, MEM_ICAP_SERVICE_LIST);
++ current = next;
++ }
++}
++
++/***************************************************
++ * icap_class
++ */
++static void
++parse_icap_class_type(IcapConfig * cfg)
++{
++ icap_class *s = NULL;
++
++ s = memAllocate(MEM_ICAP_CLASS);
++ parse_string(&s->name);
++ parse_wordlist(&s->services);
++
++ if (icap_class_process(s)) {
++ /* if ok, put into linked list */
++ icap_class_add(s);
++ } else {
++ /* clean up structure */
++ debug(3, 0) ("parse_icap_class_type (line %d): skipping %s\n", config_lineno, s->name);
++ icap_class_destroy(s);
++ memFree(s, MEM_ICAP_CLASS);
++ }
++}
++
++static void
++dump_icap_class_type(StoreEntry * e, const char *name, IcapConfig cfg)
++{
++ icap_class *current_node = NULL;
++ LOCAL_ARRAY(char, nom, 64);
++
++ if (!cfg.class_head) {
++ storeAppendPrintf(e, "%s 0\n", name);
++ return;
++ }
++ current_node = cfg.class_head;
++
++ while (current_node) {
++ snprintf(nom, 64, "%s %s", name, current_node->name);
++ dump_wordlist(e, nom, current_node->services);
++ current_node = current_node->next;
++ }
++}
++
++static void
++free_icap_class_type(IcapConfig * cfg)
++{
++ while (cfg->class_head) {
++ icap_class *current_node = cfg->class_head;
++ cfg->class_head = current_node->next;
++ icap_class_destroy(current_node);
++ memFree(current_node, MEM_ICAP_CLASS);
++ }
++}
++
++/*
++ * process services list, return 1, if at least one service was found
++ */
++static int
++icap_class_process(icap_class * c)
++{
++ icap_service_list *isl = NULL;
++ wordlist *iter;
++ icap_service *service;
++ /* take services list and build icap_service_list from it */
++ for (iter = c->services; iter; iter = iter->next) {
++ service = icap_service_lookup(iter->key);
++ if (service) {
++ icap_service_list_add(&isl, iter->key);
++ } else {
++ debug(3, 0) ("icap_class_process (line %d): skipping service %s in class %s\n", config_lineno, iter->key, c->name);
++ }
++ }
++
++ if (isl) {
++ c->isl = isl;
++ return 1;
++ }
++ return 0;
++}
++
++/*
++ * search for an icap_class in the global IcapConfig
++ * classes with hidden-flag are skipped
++ */
++static icap_class *
++icap_class_lookup(char *name)
++{
++ icap_class *iter;
++ for (iter = Config.icapcfg.class_head; iter; iter = iter->next) {
++ if ((!strcmp(name, iter->name)) && (!iter->hidden)) {
++ return iter;
++ }
++ }
++ return NULL;
++}
++
++/*
++ * adds an icap_class to the global IcapConfig
++ */
++static void
++icap_class_add(icap_class * c)
++{
++ icap_class *cp = NULL;
++ icap_class **t = NULL;
++ IcapConfig *cfg = &Config.icapcfg;
++ if (c) {
++ for (cp = cfg->class_head, t = &cfg->class_head; cp; t = &cp->next, cp = cp->next);
++ *t = c;
++ }
++}
++
++/*
++ * free allocated memory inside icap_class
++ */
++static void
++icap_class_destroy(icap_class * c)
++{
++ xfree(c->name);
++ wordlistDestroy(&c->services);
++ icap_service_list_destroy(c->isl);
++}
++
++/***************************************************
++ * icap_access
++ */
++
++/* format: icap_access <servicename> {allow|deny} acl, ... */
++static void
++parse_icap_access_type(IcapConfig * cfg)
++{
++ icap_access *A = NULL;
++ icap_access *B = NULL;
++ icap_access **T = NULL;
++ icap_service *s = NULL;
++ icap_class *c = NULL;
++ ushort no_class = 0;
++
++ A = memAllocate(MEM_ICAP_ACCESS);
++ parse_string(&A->service_name);
++
++ /*
++ * try to find a class with the given name first. if not found, search
++ * the services. if a service is found, create a new hidden class with
++ * only this service. this is for backward compatibility.
++ *
++ * the special classname All is allowed only in deny rules, because
++ * the class is not used there.
++ */
++ if (!strcmp(A->service_name, "None")) {
++ no_class = 1;
++ } else {
++ A->class = icap_class_lookup(A->service_name);
++ if (!A->class) {
++ s = icap_service_lookup(A->service_name);
++ if (s) {
++ c = memAllocate(MEM_ICAP_CLASS);
++ c->name = xstrdup("(hidden)");
++ c->hidden = 1;
++ wordlistAdd(&c->services, A->service_name);
++ c->isl = memAllocate(MEM_ICAP_SERVICE_LIST);
++ /* FIXME:luc: check what access do */
++ c->isl->services[0] = s;
++ c->isl->nservices = 1;
++ icap_class_add(c);
++ A->class = c;
++ } else {
++ debug(3, 0) ("parse_icap_access_type (line %d): servicename %s not found. skipping.\n", config_lineno, A->service_name);
++ memFree(A, MEM_ICAP_ACCESS);
++ return;
++ }
++ }
++ }
++
++ aclParseAccessLine(&(A->access));
++ debug(3, 5) ("parse_icap_access_type (line %d): %s\n", config_lineno, A->service_name);
++
++ /* check that All class is only used in deny rule */
++ if (no_class && A->access->allow) {
++ memFree(A, MEM_ICAP_ACCESS);
++ debug(3, 0) ("parse_icap_access (line %d): special class 'None' only allowed in deny rule. skipping.\n", config_lineno);
++ return;
++ }
++ if (A->access) {
++ for (B = cfg->access_head, T = &cfg->access_head; B; T = &B->next, B = B->next);
++ *T = A;
++ } else {
++ debug(3, 0) ("parse_icap_access_type (line %d): invalid line skipped\n", config_lineno);
++ memFree(A, MEM_ICAP_ACCESS);
++ }
++}
++
++static void
++dump_icap_access_type(StoreEntry * e, const char *name, IcapConfig cfg)
++{
++ icap_access *current_node = NULL;
++ LOCAL_ARRAY(char, nom, 64);
++
++ if (!cfg.access_head) {
++ storeAppendPrintf(e, "%s 0\n", name);
++ return;
++ }
++ current_node = cfg.access_head;
++
++ while (current_node) {
++ snprintf(nom, 64, "%s %s", name, current_node->service_name);
++ dump_acl_access(e, nom, current_node->access);
++ current_node = current_node->next;
++ }
++}
++
++static void
++free_icap_access_type(IcapConfig * cfg)
++{
++ while (cfg->access_head) {
++ icap_access *current_node = cfg->access_head;
++ cfg->access_head = current_node->next;
++ icap_access_destroy(current_node);
++ memFree(current_node, MEM_ICAP_ACCESS);
++ }
++}
++
++/*
++ * destructor
++ * frees everything but the linked list
++ */
++static void
++icap_access_destroy(icap_access * a)
++{
++ xfree(a->service_name);
++ aclDestroyAccessList(&a->access);
++}
++
++/***************************************************
++ * for debugging purposes only
++ */
++void
++dump_icap_config(IcapConfig * cfg)
++{
++ icap_service *s_iter;
++ icap_class *c_iter;
++ icap_access *a_iter;
++ icap_service_list *isl_iter;
++ acl_list *l;
++ debug(3, 0) ("IcapConfig: onoff = %d\n", cfg->onoff);
++ debug(3, 0) ("IcapConfig: service_head = %d\n", (int) cfg->service_head);
++ debug(3, 0) ("IcapConfig: class_head = %d\n", (int) cfg->class_head);
++ debug(3, 0) ("IcapConfig: access_head = %d\n", (int) cfg->access_head);
++
++ debug(3, 0) ("IcapConfig: services =\n");
++ for (s_iter = cfg->service_head; s_iter; s_iter = s_iter->next) {
++ printf(" %s: \n", s_iter->name);
++ printf(" bypass = %d\n", s_iter->bypass);
++ printf(" hostname = %s\n", s_iter->hostname);
++ printf(" port = %d\n", s_iter->port);
++ printf(" resource = %s\n", s_iter->resource);
++ }
++ debug(3, 0) ("IcapConfig: classes =\n");
++ for (c_iter = cfg->class_head; c_iter; c_iter = c_iter->next) {
++ printf(" %s: \n", c_iter->name);
++ printf(" services = \n");
++ for (isl_iter = c_iter->isl; isl_iter; isl_iter = isl_iter->next) {
++ int i;
++ for (i = 0; i < isl_iter->nservices; i++)
++ printf(" %s\n", isl_iter->services[i]->name);
++ }
++ }
++ debug(3, 0) ("IcapConfig: access =\n");
++ for (a_iter = cfg->access_head; a_iter; a_iter = a_iter->next) {
++ printf(" service_name = %s\n", a_iter->service_name);
++ printf(" access = %s", a_iter->access->allow ? "allow" : "deny");
++ for (l = a_iter->access->acl_list; l != NULL; l = l->next) {
++ printf(" %s%s",
++ l->op ? null_string : "!",
++ l->acl->name);
++ }
++ printf("\n");
++ }
++}
++#endif /* HS_FEAT_ICAP */
+
+ static void
+ parse_kb_size_t(squid_off_t * var)
+Index: src/cbdata.c
+===================================================================
+RCS file: /cvsroot/squid/squid/src/cbdata.c,v
+retrieving revision 1.18
+retrieving revision 1.18.8.1
+diff -p -u -b -r1.18 -r1.18.8.1
+--- src/cbdata.c 12 May 2006 22:51:56 -0000 1.18
++++ src/cbdata.c 17 May 2006 17:58:00 -0000 1.18.8.1
+@@ -179,6 +179,10 @@ cbdataInit(void)
+ CREATE_CBDATA(statefulhelper);
+ CREATE_CBDATA(helper_stateful_server);
+ CREATE_CBDATA(HttpStateData);
++#ifdef HS_FEAT_ICAP
++ CREATE_CBDATA(IcapStateData);
++ CREATE_CBDATA(icap_service);
++#endif
+ CREATE_CBDATA_FREE(peer, peerDestroy);
+ CREATE_CBDATA(ps_state);
+ CREATE_CBDATA(RemovalPolicy);
+Index: src/cf.data.pre
+===================================================================
+RCS file: /cvsroot/squid/squid/src/cf.data.pre,v
+retrieving revision 1.147
+retrieving revision 1.100.4.8
+diff -p -u -b -r1.147 -r1.100.4.8
+--- src/cf.data.pre 3 Aug 2006 02:53:44 -0000 1.147
++++ src/cf.data.pre 3 Aug 2006 17:16:02 -0000 1.100.4.8
+@@ -3178,7 +3178,6 @@ DOC_START
+ ensure correct results it is best to set server_persistent_connections
+ to off when using this directive in such configurations.
+ DOC_END
+-
+ NAME: reply_header_max_size
+ COMMENT: (KB)
+ TYPE: b_size_t
+@@ -3447,6 +3446,187 @@ DOC_START
+ DOC_END
+
+ COMMENT_START
++ ICAP OPTIONS
++ -----------------------------------------------------------------------------
++COMMENT_END
++
++NAME: icap_enable
++TYPE: onoff
++IFDEF: HS_FEAT_ICAP
++COMMENT: on|off
++LOC: Config.icapcfg.onoff
++DEFAULT: off
++DOC_START
++ If you want to enable the ICAP client module, set this to on.
++DOC_END
++
++NAME: icap_preview_enable
++TYPE: onoff
++IFDEF: HS_FEAT_ICAP
++COMMENT: on|off
++LOC: Config.icapcfg.preview_enable
++DEFAULT: off
++DOC_START
++ Set this to 'on' if you want to enable the ICAP preview
++ feature in Squid.
++DOC_END
++
++NAME: icap_preview_size
++TYPE: int
++IFDEF: HS_FEAT_ICAP
++LOC: Config.icapcfg.preview_size
++DEFAULT: -1
++DOC_START
++ The default size of preview data to be sent to the ICAP server.
++ -1 means no preview. This value might be overwritten on a per server
++ basis by OPTIONS requests.
++DOC_END
++
++NAME: icap_check_interval
++TYPE: int
++IFDEF: HS_FEAT_ICAP
++LOC: Config.icapcfg.check_interval
++DEFAULT: 300
++DOC_START
++ If an ICAP server does not respond, it gets marked as unreachable. Squid
++ will try again to reach it after this time.
++DOC_END
++
++NAME: icap_send_client_ip
++TYPE: onoff
++IFDEF: HS_FEAT_ICAP
++COMMENT: on|off
++LOC: Config.icapcfg.send_client_ip
++DEFAULT: off
++DOC_START
++ Allows Squid to add the "X-Client-IP" header if requested by
++ an ICAP service in it's response to OPTIONS.
++DOC_END
++
++NAME: icap_send_server_ip
++TYPE: onoff
++IFDEF: HS_FEAT_ICAP
++COMMENT: on|off
++LOC: Config.icapcfg.send_server_ip
++DEFAULT: off
++DOC_START
++ Allows Squid to add the "X-Server-IP" header if requested by
++ an ICAP service in it's response to OPTIONS.
++DOC_END
++
++NAME: icap_send_auth_user
++TYPE: onoff
++IFDEF: HS_FEAT_ICAP
++COMMENT: on|off
++LOC: Config.icapcfg.send_auth_user
++DEFAULT: off
++DOC_START
++ Allows Squid to add the "X-Authenticated-User" header if requested
++ by an ICAP service in it's response to OPTIONS.
++DOC_END
++
++NAME: icap_auth_scheme
++TYPE: string
++IFDEF: HS_FEAT_ICAP
++LOC: Config.icapcfg.auth_scheme
++DEFAULT: Local://%u
++DOC_START
++ Authentification scheme to pass to ICAP requests if
++ icap_send_auth_user is enabled. The first occurence of "%u"
++ is replaced by the authentified user name. If no "%u" is found,
++ the username is added at the end of the scheme.
++
++ See http://www.ietf.org/internet-drafts/draft-stecher-icap-subid-00.txt,
++ section 3.4 for details on this.
++
++ Examples:
++
++ icap_auth_scheme Local://%u
++ icap_auth_scheme LDAP://ldap-server/cn=%u,dc=company,dc=com
++ icap_auth_scheme WinNT://nt-domain/%u
++ icap_auth_scheme Radius://radius-server/%u
++DOC_END
++
++NAME: icap_service
++TYPE: icap_service_type
++IFDEF: HS_FEAT_ICAP
++LOC: Config.icapcfg
++DEFAULT: none
++DOC_START
++ Defines a single ICAP service
++
++ icap_service servicename vectoring_point bypass service_url [options ...]
++
++ vectoring_point = reqmod_precache|reqmod_postcache|respmod_precache|respmod_postcache
++ This specifies at which point of request processing the ICAP
++ service should be plugged in.
++ bypass = 1|0
++ If set to 1 and the ICAP server cannot be reached, the request will go
++ through without being processed by an ICAP server
++ service_url = icap://servername:port/service
++
++ Options:
++
++ no-keep-alive To always close the connection to icap server
++ after the transaction completes
++
++
++ Note: reqmod_precache and respmod_postcache is not yet implemented
++
++ Load-balancing and high availability:
++ You can obtain load-balancing and high availability by defining a
++ named service with different definitions. Then, the client
++ loops through the different entities of the service providing
++ load-balancing. If an entity is marked as unreachable, the client goes
++ one step further to the next entity: you have the high-availability.
++ See the service_1 definition below
++
++Example:
++icap_service service_1 reqmod_precache 0 icap://icap1.mydomain.net:1344/reqmod
++icap_service service_1 reqmod_precache 0 icap://icap2.mydomain.net:1344/reqmod no-keep-alive
++icap_service service_2 respmod_precache 0 icap://icap3.mydomain.net:1344/respmod
++DOC_END
++
++NAME: icap_class
++TYPE: icap_class_type
++IFDEF: HS_FEAT_ICAP
++LOC: Config.icapcfg
++DEFAULT: none
++DOC_START
++ Defines an ICAP service chain. If there are multiple services per
++ vectoring point, they are processed in the specified order.
++
++ icap_class classname servicename...
++
++Example:
++icap_class class_1 service_1 service_2
++icap class class_2 service_1 service_3
++DOC_END
++
++NAME: icap_access
++TYPE: icap_access_type
++IFDEF: HS_FEAT_ICAP
++LOC: Config.icapcfg
++DEFAULT: none
++DOC_START
++ Redirects a request through an ICAP service class, depending
++ on given acls
++
++ icap_access classname allow|deny [!]aclname...
++
++ The icap_access statements are processed in the order they appear in
++ this configuration file. If an access list matches, the processing stops.
++ For an "allow" rule, the specified class is used for the request. A "deny"
++ rule simply stops processing without using the class. You can also use the
++ special classname "None".
++
++ For backward compatibility, it is also possible to use services
++ directly here.
++Example:
++icap_access class_1 allow all
++DOC_END
++
++COMMENT_START
+ MISCELLANEOUS
+ -----------------------------------------------------------------------------
+ COMMENT_END
+Index: src/cf_gen_defines
+===================================================================
+RCS file: /cvsroot/squid/squid/src/cf_gen_defines,v
+retrieving revision 1.7
+retrieving revision 1.6.8.2
+diff -p -u -b -r1.7 -r1.6.8.2
+--- src/cf_gen_defines 31 May 2006 19:51:14 -0000 1.7
++++ src/cf_gen_defines 4 Jun 2006 14:15:43 -0000 1.6.8.2
+@@ -22,6 +22,7 @@ BEGIN {
+ define["USE_WCCP"]="--enable-wccp"
+ define["USE_WCCPv2"]="--enable-wccpv2"
+ define["WIP_FWD_LOG"]="--enable-forward-log"
++ define["HS_FEAT_ICAP"]="--enable-icap-support"
+ }
+ /^IFDEF:/ {
+ if (define[$2] != "")
+Index: src/client_side.c
+===================================================================
+RCS file: /cvsroot/squid/squid/src/client_side.c,v
+retrieving revision 1.138
+retrieving revision 1.89.4.10
+diff -p -u -b -r1.138 -r1.89.4.10
+--- src/client_side.c 2 Aug 2006 21:51:40 -0000 1.138
++++ src/client_side.c 3 Aug 2006 17:16:02 -0000 1.89.4.10
+@@ -109,7 +109,7 @@ static const char *const crlf = "\r\n";
+ static CWCB clientWriteComplete;
+ static CWCB clientWriteBodyComplete;
+ static PF clientReadRequest;
+-static PF connStateFree;
++PF connStateFree;
+ static PF requestTimeout;
+ static PF clientLifetimeTimeout;
+ static int clientCheckTransferDone(clientHttpRequest *);
+@@ -141,12 +141,12 @@ static void clientSetKeepaliveFlag(clien
+ 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 *);
++void clientProcessRequest(clientHttpRequest *);
+ static void clientProcessExpired(void *data);
+ static void clientProcessOnlyIfCachedMiss(clientHttpRequest * http);
+-static int clientCachable(clientHttpRequest * http);
+-static int clientHierarchical(clientHttpRequest * http);
+-static int clientCheckContentLength(request_t * r);
++int clientCachable(clientHttpRequest * http);
++int clientHierarchical(clientHttpRequest * http);
++int clientCheckContentLength(request_t * r);
+ static DEFER httpAcceptDefer;
+ static log_type clientProcessRequest2(clientHttpRequest * http);
+ static int clientReplyBodyTooLarge(clientHttpRequest *, squid_off_t clen);
+@@ -157,14 +157,17 @@ 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;
++BODY_HANDLER clientReadBody;
+ static void clientAbortBody(request_t * req);
+ #if USE_SSL
+ static void httpsAcceptSSL(ConnStateData * connState, SSL_CTX * sslContext);
+ #endif
+ static int varyEvaluateMatch(StoreEntry * entry, request_t * request);
+ static int modifiedSince(StoreEntry *, request_t *);
+-static StoreEntry *clientCreateStoreEntry(clientHttpRequest *, method_t, request_flags);
++StoreEntry *clientCreateStoreEntry(clientHttpRequest *, method_t, request_flags);
++#if HS_FEAT_ICAP
++static int clientIcapReqMod(clientHttpRequest * http);
++#endif
+
+ #if USE_IDENT
+ static void
+@@ -382,7 +385,7 @@ clientOnlyIfCached(clientHttpRequest * h
+ EBIT_TEST(r->cache_control->mask, CC_ONLY_IF_CACHED);
+ }
+
+-static StoreEntry *
++StoreEntry *
+ clientCreateStoreEntry(clientHttpRequest * h, method_t m, request_flags flags)
+ {
+ StoreEntry *e;
+@@ -642,6 +645,10 @@ clientRedirectDone(void *data, char *res
+ if (urlgroup && *urlgroup)
+ http->request->urlgroup = xstrdup(urlgroup);
+ clientInterpretRequestHeaders(http);
++#if HS_FEAT_ICAP
++ if (Config.icapcfg.onoff)
++ icapCheckAcl(http);
++#endif
+ #if HEADERS_LOG
+ headersLog(0, 1, request->method, request);
+ #endif
+@@ -1380,11 +1387,22 @@ httpRequestFree(void *data)
+ *H = http->next;
+ http->next = NULL;
+ dlinkDelete(&http->active, &ClientActiveRequests);
++#if HS_FEAT_ICAP
++ /*In the case that the upload of data breaks, we need this code here .... */
++ if (NULL != http->icap_reqmod) {
++ if (cbdataValid(http->icap_reqmod))
++ if (http->icap_reqmod->icap_fd > -1) {
++ comm_close(http->icap_reqmod->icap_fd);
++ }
++ cbdataUnlock(http->icap_reqmod);
++ http->icap_reqmod = NULL;
++ }
++#endif
+ cbdataFree(http);
+ }
+
+ /* This is a handler normally called by comm_close() */
+-static void
++void
+ connStateFree(int fd, void *data)
+ {
+ ConnStateData *connState = data;
+@@ -1401,8 +1419,9 @@ connStateFree(int fd, void *data)
+ authenticateAuthUserRequestUnlock(connState->auth_user_request);
+ connState->auth_user_request = NULL;
+ authenticateOnCloseConnection(connState);
++ if (connState->in.buf)
+ memFreeBuf(connState->in.size, connState->in.buf);
+- pconnHistCount(0, connState->nrequests);
++/* pconnHistCount(0, connState->nrequests);*/
+ if (connState->pinning.fd >= 0)
+ comm_close(connState->pinning.fd);
+ cbdataFree(connState);
+@@ -1600,7 +1619,7 @@ clientSetKeepaliveFlag(clientHttpRequest
+ }
+ }
+
+-static int
++int
+ clientCheckContentLength(request_t * r)
+ {
+ switch (r->method) {
+@@ -1619,7 +1638,7 @@ clientCheckContentLength(request_t * r)
+ /* NOT REACHED */
+ }
+
+-static int
++int
+ clientCachable(clientHttpRequest * http)
+ {
+ request_t *req = http->request;
+@@ -1645,7 +1664,7 @@ clientCachable(clientHttpRequest * http)
+ }
+
+ /* Return true if we can query our neighbors for this object */
+-static int
++int
+ clientHierarchical(clientHttpRequest * http)
+ {
+ const char *url = http->uri;
+@@ -3350,7 +3369,7 @@ clientProcessRequest2(clientHttpRequest
+ return LOG_TCP_HIT;
+ }
+
+-static void
++void
+ clientProcessRequest(clientHttpRequest * http)
+ {
+ char *url = http->uri;
+@@ -3360,6 +3379,11 @@ clientProcessRequest(clientHttpRequest *
+ debug(33, 4) ("clientProcessRequest: %s '%s'\n",
+ RequestMethodStr[r->method],
+ url);
++#if HS_FEAT_ICAP
++ if (clientIcapReqMod(http)) {
++ return;
++ }
++#endif
+ if (r->method == METHOD_CONNECT && !http->redirect.status) {
+ http->log_type = LOG_TCP_MISS;
+ #if USE_SSL && SSL_CONNECT_INTERCEPT
+@@ -3814,6 +3838,20 @@ clientReadRequest(int fd, void *data)
+ (long) conn->in.offset, (long) conn->in.size);
+ len = conn->in.size - conn->in.offset - 1;
+ }
++#if HS_FEAT_ICAP
++ /*
++ * This check exists because ICAP doesn't always work well
++ * with persistent (reused) connections. One version of the
++ * REQMOD code creates a fake ConnStateData, which doesn't have
++ * an in.buf. We want to make sure that the fake ConnStateData
++ * doesn't get used here.
++ */
++ if (NULL == conn->in.buf) {
++ debug(33, 1) ("clientReadRequest: FD %d aborted; conn->in.buf is NULL\n", fd);
++ comm_close(fd);
++ return;
++ }
++#endif
+ statCounter.syscalls.sock.reads++;
+ size = FD_READ_METHOD(fd, conn->in.buf + conn->in.offset, len);
+ if (size > 0) {
+@@ -3917,7 +3955,8 @@ clientReadRequest(int fd, void *data)
+ /* add to the client request queue */
+ for (H = &conn->chr; *H; H = &(*H)->next);
+ *H = http;
+- conn->nrequests++;
++ F->pconn.uses++;
++ F->pconn.type = 0;
+ /*
+ * I wanted to lock 'http' here since its callback data for
+ * clientLifetimeTimeout(), but there's no logical place to
+@@ -4100,7 +4139,7 @@ clientReadRequest(int fd, void *data)
+ }
+
+ /* file_read like function, for reading body content */
+-static void
++void
+ clientReadBody(request_t * request, char *buf, size_t size, CBCB * callback, void *cbdata)
+ {
+ ConnStateData *conn = request->body_reader_data;
+@@ -4229,7 +4268,7 @@ clientProcessBody(ConnStateData * conn)
+ }
+
+ /* Abort a body request */
+-static void
++void
+ clientAbortBody(request_t * request)
+ {
+ ConnStateData *conn = request->body_reader_data;
+@@ -4271,7 +4310,7 @@ requestTimeout(int fd, void *data)
+ * Some data has been sent to the client, just close the FD
+ */
+ comm_close(fd);
+- } else if (conn->nrequests) {
++ } else if (fd_table[fd].pconn.uses) {
+ /*
+ * assume its a persistent connection; just close it
+ */
+@@ -5007,6 +5046,52 @@ varyEvaluateMatch(StoreEntry * entry, re
+ }
+ }
+
++#if HS_FEAT_ICAP
++static int
++clientIcapReqMod(clientHttpRequest * http)
++{
++ ErrorState *err;
++ icap_service *service;
++ if (http->flags.did_icap_reqmod)
++ return 0;
++ if (NULL == (service = icapService(ICAP_SERVICE_REQMOD_PRECACHE, http->request)))
++ return 0;
++ debug(33, 3) ("clientIcapReqMod: calling icapReqModStart for %p\n", http);
++ /*
++ * Note, we pass 'start' and 'log_addr' to ICAP so the access.log
++ * entry comes out right. The 'clientHttpRequest' created by
++ * the ICAP side is the one that gets logged. The first
++ * 'clientHttpRequest' does not get logged because its out.size
++ * is zero and log_type is unset.
++ */
++ http->icap_reqmod = icapReqModStart(service,
++ http->uri,
++ http->request,
++ http->conn->fd,
++ http->start,
++ http->conn->log_addr,
++ (void *) http->conn);
++ if (NULL == http->icap_reqmod) {
++ return 0;
++ } else if (-1 == (int) http->icap_reqmod) {
++ /* produce error */
++ http->icap_reqmod = NULL;
++ debug(33, 2) ("clientIcapReqMod: icap told us to send an error\n");
++ http->log_type = LOG_TCP_DENIED;
++ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
++ err->xerrno = ETIMEDOUT;
++ err->request = requestLink(http->request);
++ err->src_addr = http->conn->peer.sin_addr;
++ http->entry = clientCreateStoreEntry(http, http->request->method, null_request_flags);
++ errorAppendEntry(http->entry, err);
++ return 1;
++ }
++ cbdataLock(http->icap_reqmod);
++ http->flags.did_icap_reqmod = 1;
++ return 1;
++}
++#endif
++
+ /* This is a handler normally called by comm_close() */
+ static void
+ clientPinnedConnectionClosed(int fd, void *data)
+Index: src/comm.c
+===================================================================
+RCS file: /cvsroot/squid/squid/src/comm.c,v
+retrieving revision 1.44
+retrieving revision 1.29.10.6
+diff -p -u -b -r1.44 -r1.29.10.6
+--- src/comm.c 27 Jun 2006 11:52:53 -0000 1.44
++++ src/comm.c 28 Jun 2006 21:11:59 -0000 1.29.10.6
+@@ -736,8 +736,8 @@ comm_close(int fd)
+ F->flags.closing = 1;
+ CommWriteStateCallbackAndFree(fd, COMM_ERR_CLOSING);
+ commCallCloseHandlers(fd);
+- if (F->uses) /* assume persistent connect count */
+- pconnHistCount(1, F->uses);
++ if (F->pconn.uses)
++ pconnHistCount(F->pconn.type, F->pconn.uses);
+ #if USE_SSL
+ if (F->ssl) {
+ if (!F->flags.close_request) {
+Index: src/enums.h
+===================================================================
+RCS file: /cvsroot/squid/squid/src/enums.h,v
+retrieving revision 1.56
+retrieving revision 1.45.4.5
+diff -p -u -b -r1.56 -r1.45.4.5
+--- src/enums.h 19 Jul 2006 17:52:44 -0000 1.56
++++ src/enums.h 22 Jul 2006 14:12:01 -0000 1.45.4.5
+@@ -93,6 +93,7 @@ typedef enum {
+ ERR_ONLY_IF_CACHED_MISS, /* failure to satisfy only-if-cached request */
+ ERR_TOO_BIG,
+ TCP_RESET,
++ ERR_ICAP_FAILURE,
+ ERR_INVALID_RESP,
+ ERR_MAX
+ } err_type;
+@@ -455,6 +456,9 @@ typedef enum {
+ PROTO_WHOIS,
+ PROTO_INTERNAL,
+ PROTO_HTTPS,
++#if HS_FEAT_ICAP
++ PROTO_ICAP,
++#endif
+ PROTO_MAX
+ } protocol_t;
+
+@@ -632,6 +636,12 @@ typedef enum {
+ #if USE_SSL
+ MEM_ACL_CERT_DATA,
+ #endif
++#if HS_FEAT_ICAP
++ MEM_ICAP_OPT_DATA,
++ MEM_ICAP_SERVICE_LIST,
++ MEM_ICAP_CLASS,
++ MEM_ICAP_ACCESS,
++#endif
+ MEM_MAX
+ } mem_type;
+
+@@ -732,9 +742,14 @@ typedef enum {
+ CBDATA_RemovalPolicyWalker,
+ CBDATA_RemovalPurgeWalker,
+ CBDATA_store_client,
++#ifdef HS_FEAT_ICAP
++ CBDATA_IcapStateData,
++ CBDATA_icap_service,
++#endif
+ CBDATA_FIRST_CUSTOM_TYPE = 1000
+ } cbdata_type;
+
++
+ /*
+ * Return codes from checkVary(request)
+ */
+@@ -782,4 +797,68 @@ typedef enum {
+ ST_OP_CREATE
+ } store_op_t;
+
++#if HS_FEAT_ICAP
++typedef enum {
++ ICAP_STATUS_NONE = 0,
++ ICAP_STATUS_CONTINUE = 100,
++ ICAP_STATUS_SWITCHING_PROTOCOLS = 101,
++ ICAP_STATUS_STATUS_OK = 200,
++ ICAP_CREATED = 201,
++ ICAP_STATUS_ACCEPTED = 202,
++ ICAP_STATUS_NON_AUTHORITATIVE_INFORMATION = 203,
++ ICAP_STATUS_NO_MODIFICATION_NEEDED = 204,
++ ICAP_STATUS_RESET_CONTENT = 205,
++ ICAP_STATUS_PARTIAL_CONTENT = 206,
++ ICAP_STATUS_MULTIPLE_CHOICES = 300,
++ ICAP_STATUS_MOVED_PERMANENTLY = 301,
++ ICAP_STATUS_MOVED_TEMPORARILY = 302,
++ ICAP_STATUS_SEE_OTHER = 303,
++ ICAP_STATUS_NOT_MODIFIED = 304,
++ ICAP_STATUS_USE_PROXY = 305,
++ ICAP_STATUS_BAD_REQUEST = 400,
++ ICAP_STATUS_UNAUTHORIZED = 401,
++ ICAP_STATUS_PAYMENT_REQUIRED = 402,
++ ICAP_STATUS_FORBIDDEN = 403,
++ ICAP_STATUS_SERVICE_NOT_FOUND = 404,
++ ICAP_STATUS_METHOD_NOT_ALLOWED = 405,
++ ICAP_STATUS_NOT_ACCEPTABLE = 406,
++ ICAP_STATUS_PROXY_AUTHENTICATION_REQUIRED = 407,
++ ICAP_STATUS_REQUEST_TIMEOUT = 408,
++ ICAP_STATUS_CONFLICT = 409,
++ ICAP_STATUS_GONE = 410,
++ ICAP_STATUS_LENGTH_REQUIRED = 411,
++ ICAP_STATUS_PRECONDITION_FAILED = 412,
++ ICAP_STATUS_REQUEST_ENTITY_TOO_LARGE = 413,
++ ICAP_STATUS_REQUEST_URI_TOO_LARGE = 414,
++ ICAP_STATUS_UNSUPPORTED_MEDIA_TYPE = 415,
++ ICAP_STATUS_INTERNAL_SERVER_ERROR = 500,
++ ICAP_STATUS_NOT_IMPLEMENTED = 501,
++ ICAP_STATUS_BAD_GATEWAY = 502,
++ ICAP_STATUS_SERVICE_OVERLOADED = 503,
++ ICAP_STATUS_GATEWAY_TIMEOUT = 504,
++ ICAP_STATUS_ICAP_VERSION_NOT_SUPPORTED = 505,
++ ICAP_STATUS_INVALID_HEADER = 600
++} icap_status;
++
++/*
++ * these values are used as index in an array, so it seems to be better to
++ * assign some numbers
++ */
++typedef enum {
++ ICAP_SERVICE_REQMOD_PRECACHE = 0,
++ ICAP_SERVICE_REQMOD_POSTCACHE = 1,
++ ICAP_SERVICE_RESPMOD_PRECACHE = 2,
++ ICAP_SERVICE_RESPMOD_POSTCACHE = 3,
++ ICAP_SERVICE_MAX = 4
++} icap_service_t;
++
++typedef enum {
++ ICAP_METHOD_NONE,
++ ICAP_METHOD_OPTION,
++ ICAP_METHOD_REQMOD,
++ ICAP_METHOD_RESPMOD
++} icap_method_t;
++
++#endif /* HS_FEAT_ICAP */
++
+ #endif /* SQUID_ENUMS_H */
+Index: src/forward.c
+===================================================================
+RCS file: /cvsroot/squid/squid/src/forward.c,v
+retrieving revision 1.40
+retrieving revision 1.20.4.7
+diff -p -u -b -r1.40 -r1.20.4.7
+--- src/forward.c 30 Jun 2006 21:52:14 -0000 1.40
++++ src/forward.c 22 Jul 2006 14:12:01 -0000 1.20.4.7
+@@ -362,8 +362,9 @@ fwdConnectDone(int server_fd, int status
+ } else {
+ debug(17, 3) ("fwdConnectDone: FD %d: '%s'\n", server_fd, storeUrl(fwdState->entry));
+ fd_note(server_fd, storeUrl(fwdState->entry));
+- fd_table[server_fd].uses++;
+- if (fd_table[server_fd].uses == 1 && fs->peer)
++ fd_table[server_fd].pconn.uses++;
++ fd_table[server_fd].pconn.type = 1;
++ if (fd_table[server_fd].pconn.uses ==1 && fs->peer)
+ peerConnectSucceded(fs->peer);
+ #if USE_SSL
+ if ((fs->peer && fs->peer->use_ssl) ||
+@@ -941,6 +942,8 @@ fwdCheckDeferRead(int fd, void *data)
+ void
+ fwdFail(FwdState * fwdState, ErrorState * errorState)
+ {
++ if (NULL == fwdState)
++ return;
+ debug(17, 3) ("fwdFail: %s \"%s\"\n\t%s\n",
+ err_type_str[errorState->type],
+ httpStatusString(errorState->http_status),
+@@ -979,6 +982,8 @@ fwdPeerClosed(int fd, void *data)
+ void
+ fwdUnregister(int fd, FwdState * fwdState)
+ {
++ if (NULL == fwdState)
++ return;
+ debug(17, 3) ("fwdUnregister: %s\n", storeUrl(fwdState->entry));
+ assert(fd == fwdState->server_fd);
+ assert(fd > -1);
+@@ -998,7 +1003,10 @@ fwdUnregister(int fd, FwdState * fwdStat
+ void
+ fwdComplete(FwdState * fwdState)
+ {
+- StoreEntry *e = fwdState->entry;
++ StoreEntry *e;
++ if (NULL == fwdState)
++ return;
++ e = fwdState->entry;
+ assert(e->store_status == STORE_PENDING);
+ debug(17, 3) ("fwdComplete: %s\n\tstatus %d\n", storeUrl(e),
+ e->mem_obj->reply->sline.status);
+Index: src/globals.h
+===================================================================
+RCS file: /cvsroot/squid/squid/src/globals.h,v
+retrieving revision 1.26
+retrieving revision 1.22.4.4
+diff -p -u -b -r1.26 -r1.22.4.4
+--- src/globals.h 30 Jul 2006 23:52:54 -0000 1.26
++++ src/globals.h 3 Aug 2006 17:16:04 -0000 1.22.4.4
+@@ -171,6 +171,9 @@ extern const char *external_acl_message;
+ #if HAVE_SBRK
+ extern void *sbrk_start; /* 0 */
+ #endif
++#if HS_FEAT_ICAP
++extern char *icap_service_type_str[];
++#endif
+ extern int opt_send_signal; /* -1 */
+ extern int opt_no_daemon; /* 0 */
+ #if LINUX_TPROXY
+Index: src/http.c
+===================================================================
+RCS file: /cvsroot/squid/squid/src/http.c,v
+retrieving revision 1.47
+retrieving revision 1.28.4.9
+diff -p -u -b -r1.47 -r1.28.4.9
+--- src/http.c 26 Jul 2006 20:51:25 -0000 1.47
++++ src/http.c 3 Aug 2006 17:16:04 -0000 1.28.4.9
+@@ -47,7 +47,7 @@ static CWCB httpSendRequestEntry;
+
+ static PF httpReadReply;
+ static void httpSendRequest(HttpStateData *);
+-static PF httpStateFree;
++PF httpStateFree;
+ static PF httpTimeout;
+ static void httpCacheNegatively(StoreEntry *);
+ static void httpMakePrivate(StoreEntry *);
+@@ -56,11 +56,12 @@ static int httpCachableReply(HttpStateDa
+ static void httpMaybeRemovePublic(StoreEntry *, http_status);
+ static int peer_supports_connection_pinning(HttpStateData * httpState);
+
+-static void
++void
+ httpStateFree(int fd, void *data)
+ {
+ HttpStateData *httpState = data;
+ #if DELAY_POOLS
++ if (fd >= 0)
+ delayClearNoDelay(fd);
+ #endif
+ if (httpState == NULL)
+@@ -80,6 +81,9 @@ httpStateFree(int fd, void *data)
+ requestUnlink(httpState->orig_request);
+ httpState->request = NULL;
+ httpState->orig_request = NULL;
++#if HS_FEAT_ICAP
++ cbdataUnlock(httpState->icap_writer);
++#endif
+ cbdataFree(httpState);
+ }
+
+@@ -409,7 +413,7 @@ httpMakeVaryMark(request_t * request, Ht
+ }
+
+ /* rewrite this later using new interfaces @?@ */
+-static void
++void
+ httpProcessReplyHeader(HttpStateData * httpState, const char *buf, int size)
+ {
+ StoreEntry *entry = httpState->entry;
+@@ -551,24 +555,35 @@ httpPconnTransferDone(HttpStateData * ht
+ MemObject *mem = httpState->entry->mem_obj;
+ HttpReply *reply = mem->reply;
+ squid_off_t clen;
++ squid_off_t content_bytes_read;
+ debug(11, 3) ("httpPconnTransferDone: FD %d\n", httpState->fd);
+ debug(11, 5) ("httpPconnTransferDone: content_length=%" PRINTF_OFF_T "\n",
+ reply->content_length);
+ /* If we haven't seen the end of reply headers, we are not done */
+- if (httpState->reply_hdr_state < 2)
++ if (httpState->reply_hdr_state < 2) {
++ debug(11, 3) ("httpPconnTransferDone: reply_hdr_state=%d, returning 0\n",
++ httpState->reply_hdr_state);
+ return 0;
++ }
+ clen = httpReplyBodySize(httpState->request->method, reply);
++#ifdef HS_FEAT_ICAP
++ if (httpState->icap_writer) {
++ content_bytes_read = httpState->icap_writer->fake_content_length;
++ debug(11, 3) ("using fake conten length %" PRINTF_OFF_T "\n", content_bytes_read);
++ } else
++#endif
++ content_bytes_read = mem->inmem_hi;
+ /* If the body size is unknown we must wait for EOF */
+ if (clen < 0)
+ return 0;
+ /* Barf if we got more than we asked for */
+- if (mem->inmem_hi > clen + reply->hdr_sz)
++ if (content_bytes_read > clen + reply->hdr_sz)
+ return -1;
+ /* If there is no message body, we can be persistent */
+ if (0 == clen)
+ return 1;
+ /* If the body size is known, we must wait until we've gotten all of it. */
+- if (mem->inmem_hi < clen + reply->hdr_sz)
++ if (content_bytes_read < clen + reply->hdr_sz)
+ return 0;
+ /* We got it all */
+ return 1;
+@@ -635,6 +650,17 @@ httpReadReply(int fd, void *data)
+ delay_id delay_id;
+ #endif
+
++#if HS_FEAT_ICAP
++ if (httpState->icap_writer) {
++ if (!httpState->icap_writer->respmod.entry) {
++ debug(11, 3) ("httpReadReply: FD: %d: icap respmod aborded!\n", fd);
++ comm_close(fd);
++ return;
++ }
++ /*The folowing entry can not be marked as aborted.
++ * The StoreEntry icap_writer->respmod.entry used when the icap_write used...... */
++ } else
++#endif
+ if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
+ comm_close(fd);
+ return;
+@@ -646,7 +672,35 @@ httpReadReply(int fd, void *data)
+ else
+ delay_id = delayMostBytesAllowed(entry->mem_obj, &read_sz);
+ #endif
++#if HS_FEAT_ICAP
++ if (httpState->icap_writer) {
++ IcapStateData *icap = httpState->icap_writer;
++ /*
++ * Ok we have a received a response from the web server, so try to
++ * connect the icap server if it's the first attemps. If we try
++ * to connect to the icap server, defer this request (do not read
++ * the buffer), and defer until icapConnectOver() is not called.
++ */
++ if (icap->flags.connect_requested == 0) {
++ debug(81, 2) ("icapSendRespMod: Create a new connection to icap server\n");
++ if (!icapConnect(icap, icapConnectOver)) {
++ debug(81, 2) ("icapSendRespMod: Something strange while creating a socket to icap server\n");
++ commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
++ return;
++ }
++ debug(81, 2) ("icapSendRespMod: new connection to icap server (using FD=%d)\n", icap->icap_fd);
++ icap->flags.connect_requested = 1;
++ /* Wait for more data or EOF condition */
++ commSetTimeout(fd, httpState->flags.keepalive_broken ? 10 : Config.Timeout.read, NULL, NULL);
++ commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
++ return;
++ }
+
++ if(icap->flags.no_content == 1) {
++ commSetDefer(fd, fwdCheckDeferRead, icap->respmod.entry);
++ }
++ }
++#endif
+ errno = 0;
+ statCounter.syscalls.sock.reads++;
+ len = FD_READ_METHOD(fd, buf, read_sz);
+@@ -663,7 +717,13 @@ httpReadReply(int fd, void *data)
+ clen >>= 1;
+ IOStats.Http.read_hist[bin]++;
+ }
+- if (!httpState->reply_hdr.size && len > 0 && fd_table[fd].uses > 1) {
++#ifdef HS_FEAT_ICAP
++ if (httpState->icap_writer)
++ (void) 0;
++ else
++#endif
++
++ if (!httpState->reply_hdr.size && len > 0 && fd_table[fd].pconn.uses > 1) {
+ /* Skip whitespace */
+ while (len > 0 && xisspace(*buf))
+ xmemmove(buf, buf + 1, len--);
+@@ -693,6 +753,12 @@ httpReadReply(int fd, void *data)
+ } else if (len == 0) {
+ /* Connection closed; retrieval done. */
+ httpState->eof = 1;
++#ifdef HS_FEAT_ICAP
++ if (httpState->icap_writer && cbdataValid(httpState->icap_writer)) {
++ debug(81, 3) ("httpReadReply: EOF for ICAP writer\n");
++ icapSendRespMod(httpState->icap_writer, buf, len, 1);
++ }
++#endif
+ if (httpState->reply_hdr_state < 2)
+ /*
+ * Yes Henrik, there is a point to doing this. When we
+@@ -745,7 +811,28 @@ httpReadReply(int fd, void *data)
+ EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
+ }
+ }
++#ifdef HS_FEAT_ICAP
++ if (httpState->icap_writer) {
++ debug(81, 5) ("calling icapSendRespMod from %s:%d\n", __FILE__, __LINE__);
++ if (cbdataValid(httpState->icap_writer)) {
++ icapSendRespMod(httpState->icap_writer, buf, len, 0);
++ httpState->icap_writer->fake_content_length += len;
++ }
++ } else
++#endif
+ storeAppend(entry, buf, len);
++
++
++ debug(11, 5) ("httpReadReply: after storeAppend FD %d read %d\n", fd, len);
++#if HS_FEAT_ICAP
++ if (httpState->icap_writer) {
++ if (!httpState->icap_writer->respmod.entry) {
++ debug(11, 3) ("httpReadReply: FD: %d: icap respmod aborded!\n", fd);
++ comm_close(fd);
++ return;
++ }
++ } else
++#endif
+ if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
+ /*
+ * the above storeAppend() call could ABORT this entry,
+@@ -792,10 +879,21 @@ httpReadReply(int fd, void *data)
+ ("httpReadReply: Excess data from \"%s %s\"\n",
+ RequestMethodStr[orig_request->method],
+ storeUrl(entry));
++#ifdef HS_FEAT_ICAP
++ if (httpState->icap_writer) {
++ debug(81, 5) ("calling icapSendRespMod from %s:%d\n", __FILE__, __LINE__);
++ icapSendRespMod(httpState->icap_writer, buf, len, 0);
++ httpState->icap_writer->fake_content_length += len;
++ } else
++#endif
+ storeAppend(entry, buf, len);
+ keep_alive = 0;
+ }
+ }
++#ifdef HS_FEAT_ICAP
++ if (httpState->icap_writer)
++ icapSendRespMod(httpState->icap_writer, NULL, 0, 1);
++#endif
+ if (keep_alive) {
+ int pinned = 0;
+ #if LINUX_TPROXY
+@@ -851,6 +949,10 @@ httpReadReply(int fd, void *data)
+ ("httpReadReply: Excess data from \"%s %s\"\n",
+ RequestMethodStr[orig_request->method],
+ storeUrl(entry));
++#ifdef HS_FEAT_ICAP
++ if (httpState->icap_writer)
++ icapSendRespMod(httpState->icap_writer, NULL, 0, 1);
++#endif
+ fwdComplete(httpState->fwd);
+ comm_close(fd);
+ return;
+@@ -861,6 +963,34 @@ httpReadReply(int fd, void *data)
+ }
+ }
+
++#ifdef HS_FEAT_ICAP
++static int
++httpReadReplyWaitForIcap(int fd, void *data)
++{
++ HttpStateData *httpState = data;
++ if (NULL == httpState->icap_writer)
++ return 0;
++ /*
++ * Do not defer when we are not connected to the icap server.
++ * Defer when the icap server connection is not established but pending
++ * Defer when the icap server is busy (writing on the socket)
++ */
++ debug(11, 5) ("httpReadReplyWaitForIcap: FD %d, connect_requested=%d\n",
++ fd, httpState->icap_writer->flags.connect_requested);
++ if (!httpState->icap_writer->flags.connect_requested)
++ return 0;
++ debug(11, 5) ("httpReadReplyWaitForIcap: FD %d, connect_pending=%d\n",
++ fd, httpState->icap_writer->flags.connect_pending);
++ if (httpState->icap_writer->flags.connect_pending)
++ return 1;
++ debug(11, 5) ("httpReadReplyWaitForIcap: FD %d, write_pending=%d\n",
++ fd, httpState->icap_writer->flags.write_pending);
++ if (httpState->icap_writer->flags.write_pending)
++ return 1;
++ return 0;
++}
++#endif
++
+ /* This will be called when request write is complete. Schedule read of
+ * reply. */
+ static void
+@@ -888,6 +1018,63 @@ httpSendComplete(int fd, char *bufnotuse
+ comm_close(fd);
+ return;
+ } else {
++ /* Schedule read reply. */
++#ifdef HS_FEAT_ICAP
++ if (icapService(ICAP_SERVICE_RESPMOD_PRECACHE, httpState->orig_request)) {
++ httpState->icap_writer = icapRespModStart(
++ ICAP_SERVICE_RESPMOD_PRECACHE,
++ httpState->orig_request, httpState->entry, httpState->flags);
++ if (-1 == (int) httpState->icap_writer) {
++ /* TODO: send error here and exit */
++ ErrorState *err;
++ httpState->icap_writer = 0;
++ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
++ err->xerrno = errno;
++ err->request = requestLink(httpState->orig_request);
++ errorAppendEntry(entry, err);
++ comm_close(fd);
++ return;
++ } else if (httpState->icap_writer) {
++ request_flags fake_flags = httpState->orig_request->flags;
++ method_t fake_method = entry->mem_obj->method;
++ const char *fake_msg = "this is a fake entry for "
++ " response sent to an ICAP RESPMOD server";
++ cbdataLock(httpState->icap_writer);
++ /*
++ * this httpState will give the data it reads to
++ * the icap server, rather than put it into
++ * a StoreEntry
++ */
++ storeClientUnregisterAbort(httpState->entry);
++ storeUnlockObject(httpState->entry);
++ /*
++ * create a bogus entry because the code assumes one is
++ * always there.
++ */
++ fake_flags.cachable = 0;
++ fake_flags.hierarchical = 0; /* force private key */
++ httpState->entry = storeCreateEntry("fake", "fake", fake_flags, fake_method);
++ storeAppend(httpState->entry, fake_msg, strlen(fake_msg));
++ /*
++ * pull a switcheroo on fwdState->entry.
++ */
++ storeUnlockObject(httpState->fwd->entry);
++ httpState->fwd->entry = httpState->entry;
++ storeLockObject(httpState->fwd->entry);
++ /*
++ * Note that we leave fwdState connected to httpState,
++ * but we changed the entry. So when fwdComplete
++ * or whatever is called it does no harm -- its
++ * just the fake entry.
++ */
++ } else {
++ /*
++ * failed to open connection to ICAP server.
++ * But bypass request, so just continue here.
++ */
++ }
++ }
++#endif
+ /*
+ * Set the read timeout here because it hasn't been set yet.
+ * We only set the read timeout after the request has been
+@@ -896,8 +1083,18 @@ httpSendComplete(int fd, char *bufnotuse
+ * the timeout for POST/PUT requests that have very large
+ * request bodies.
+ */
++
++ /* removed in stable5:
++ * commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
++ */
+ commSetTimeout(fd, Config.Timeout.read, httpTimeout, httpState);
+- commSetDefer(fd, fwdCheckDeferRead, entry);
++#ifdef HS_FEAT_ICAP
++ if (httpState->icap_writer) {
++ debug(11, 5) ("FD %d, setting httpReadReplyWaitForIcap\n", httpState->fd);
++ commSetDefer(httpState->fd, httpReadReplyWaitForIcap, httpState);
++ } else
++#endif
++ commSetDefer(httpState->fd, fwdCheckDeferRead, entry);
+ }
+ httpState->flags.request_sent = 1;
+ }
+@@ -1191,8 +1388,11 @@ httpBuildRequestHeader(request_t * reque
+ if (!EBIT_TEST(cc->mask, CC_MAX_AGE)) {
+ const char *url = entry ? storeUrl(entry) : urlCanonical(orig_request);
+ httpHdrCcSetMaxAge(cc, getMaxAge(url));
++#ifndef HS_FEAT_ICAP
++ /* Don;t bother - if the url you want to cache is redirected? */
+ if (strLen(request->urlpath))
+ assert(strstr(url, strBuf(request->urlpath)));
++#endif
+ }
+ /* Set no-cache if determined needed but not found */
+ if (orig_request->flags.nocache && !httpHeaderHas(hdr_in, HDR_PRAGMA))
+@@ -1318,6 +1518,7 @@ httpStart(FwdState * fwd)
+ int fd = fwd->server_fd;
+ HttpStateData *httpState;
+ request_t *proxy_req;
++ /* ErrorState *err; */
+ request_t *orig_req = fwd->request;
+ debug(11, 3) ("httpStart: \"%s %s\"\n",
+ RequestMethodStr[orig_req->method],
+@@ -1360,12 +1561,22 @@ httpStart(FwdState * fwd)
+ httpState->request = requestLink(orig_req);
+ httpState->orig_request = requestLink(orig_req);
+ }
++#ifdef HS_FEAT_ICAP
++ if (icapService(ICAP_SERVICE_REQMOD_POSTCACHE, httpState->orig_request)) {
++ httpState->icap_writer = icapRespModStart(ICAP_SERVICE_REQMOD_POSTCACHE,
++ httpState->orig_request, httpState->entry, httpState->flags);
++ if (httpState->icap_writer) {
++ return;
++ }
++ }
++#endif
+ /*
+ * register the handler to free HTTP state data when the FD closes
+ */
+ comm_add_close_handler(fd, httpStateFree, httpState);
+ statCounter.server.all.requests++;
+ statCounter.server.http.requests++;
++
+ httpSendRequest(httpState);
+ /*
+ * We used to set the read timeout here, but not any more.
+Index: src/icap_common.c
+===================================================================
+RCS file: src/icap_common.c
+diff -N src/icap_common.c
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ src/icap_common.c 26 May 2006 19:24:02 -0000 1.1.14.3
+@@ -0,0 +1,815 @@
++/*
++ * $Id$
++ *
++ * DEBUG: section 81 Internet Content Adaptation Protocol (ICAP) Client
++ * AUTHOR: Geetha Manjunath, Hewlett Packard Company
++ *
++ * 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.
++ *
++ */
++
++/* _GNU_SOURCE is required for strcasestr */
++#define _GNU_SOURCE 1
++
++#include "squid.h"
++#include "util.h"
++
++extern PF httpStateFree;
++
++#define EXPECTED_ICAP_HEADER_LEN 256
++#define ICAP_OPTIONS_REQUEST
++
++
++void
++icapInit()
++{
++#ifdef ICAP_OPTIONS_REQUEST
++ if (Config.icapcfg.onoff) {
++ icapOptInit();
++ }
++#endif
++}
++
++void
++icapClose()
++{
++ icapOptShutdown();
++}
++
++/*
++ * search for a HTTP-like header in the buffer.
++ * Note, buf must be 0-terminated
++ *
++ * This function is not very good. It should probably look for
++ * header tokens only at the start of a line, not just anywhere in
++ * the buffer.
++ */
++int
++icapFindHeader(const char *buf, const char *hdr, const char **Start,
++ const char **End)
++{
++ const char *start = NULL;
++ const char *end = NULL;
++ start = strcasestr(buf, hdr);
++ if (NULL == start)
++ return 0;
++ end = start + strcspn(start, "\r\n");
++ if (start == end)
++ return 0;
++ *Start = start;
++ *End = end;
++ return 1;
++}
++
++/*
++ * parse the contents of the encapsulated header (buffer between enc_start
++ * and enc_end) and put the result into IcapStateData
++ */
++void
++icapParseEncapsulated(IcapStateData * icap, const char *enc_start,
++ const char *enc_end)
++{
++ char *current, *end;
++
++ assert(icap);
++ assert(enc_start);
++ assert(enc_end);
++
++ current = strchr(enc_start, ':');
++ current++;
++ while (current < enc_end) {
++ while (isspace(*current))
++ current++;
++ if (!strncmp(current, "res-hdr=", 8)) {
++ current += 8;
++ icap->enc.res_hdr = strtol(current, &end, 10);
++ } else if (!strncmp(current, "req-hdr=", 8)) {
++ current += 8;
++ icap->enc.req_hdr = strtol(current, &end, 10);
++ } else if (!strncmp(current, "null-body=", 10)) {
++ current += 10;
++ icap->enc.null_body = strtol(current, &end, 10);
++ } else if (!strncmp(current, "res-body=", 9)) {
++ current += 9;
++ icap->enc.res_body = strtol(current, &end, 10);
++ } else if (!strncmp(current, "req-body=", 9)) {
++ current += 9;
++ icap->enc.req_body = strtol(current, &end, 10);
++ } else if (!strncmp(current, "opt-body=", 9)) {
++ current += 9;
++ icap->enc.opt_body = strtol(current, &end, 10);
++ } else {
++ /* invalid header */
++ debug(81, 5) ("icapParseEncapsulated: error in: %s\n", current);
++ return;
++ }
++ current = end;
++ current = strchr(current, ',');
++ if (current == NULL)
++ break;
++ else
++ current++; /* skip ',' */
++ }
++ debug(81,
++ 3) ("icapParseEncapsulated: res-hdr=%d, req-hdr=%d, null-body=%d, "
++ "res-body=%d, req-body=%d, opt-body=%d\n", icap->enc.res_hdr,
++ icap->enc.req_hdr, icap->enc.null_body, icap->enc.res_body,
++ icap->enc.req_body, icap->enc.opt_body);
++
++}
++
++icap_service *
++icapService(icap_service_t type, request_t * r)
++{
++ icap_service_list *isl_iter;
++ int is_iter;
++ int nb_unreachable = 0;
++ icap_service *unreachable_one = NULL;
++
++ debug(81, 8) ("icapService: type=%s\n", icapServiceToStr(type));
++ if (NULL == r) {
++ debug(81, 8) ("icapService: no request_t\n");
++ return NULL;
++ }
++ if (NULL == r->class) {
++ debug(81, 8) ("icapService: no class\n");
++ return NULL;
++ }
++ for (isl_iter = r->class->isl; isl_iter; isl_iter = isl_iter->next) {
++ /* TODO:luc: Do a round-robin, choose a random value ?
++ * For now, we use a simple round robin with checking is the
++ * icap server is available */
++ is_iter = isl_iter->last_service_used;
++ do {
++ is_iter = (is_iter + 1) % isl_iter->nservices;
++ debug(81, 8) ("icapService: checking service %s/id=%d\n",
++ isl_iter->services[is_iter]->name, is_iter);
++ if (type == isl_iter->services[is_iter]->type) {
++ if (!isl_iter->services[is_iter]->unreachable) {
++ debug(81, 8) ("icapService: found service %s/id=%d\n",
++ isl_iter->services[is_iter]->name, is_iter);
++ isl_iter->last_service_used = is_iter;
++ return isl_iter->services[is_iter];
++ }
++ debug(81,
++ 8)
++ ("icapService: found service %s/id=%d, but it's unreachable. I don't want to use it\n",
++ isl_iter->services[is_iter]->name, is_iter);
++ unreachable_one = isl_iter->services[is_iter];
++ nb_unreachable++;
++ /* FIXME:luc: in response mod, if we return an NULL pointer, user can bypass
++ * the filter, is it normal ? */
++ }
++ } while (is_iter != isl_iter->last_service_used);
++ }
++ debug(81, 8) ("icapService: no service found\n");
++ isl_iter = r->class->isl;
++
++ if (nb_unreachable > 0) {
++ debug(81,
++ 8)
++ ("All the services are unreachable, returning an unreachable one\n");
++ return unreachable_one;
++ } else {
++ return NULL;
++ }
++}
++
++int
++icapConnect(IcapStateData * icap, CNCB * theCallback)
++{
++ int rc;
++ icap->icap_fd = pconnPop(icap->current_service->hostname,
++ icap->current_service->port, NULL, NULL, 0);
++ if (icap->icap_fd >= 0) {
++ debug(81, 3) ("icapConnect: reused pconn FD %d\n", icap->icap_fd);
++ fd_note(icap->icap_fd, icap->current_service->uri);
++ comm_add_close_handler(icap->icap_fd, icapStateFree, icap);
++ theCallback(icap->icap_fd, 0, icap);
++ return 1;
++ }
++ icap->icap_fd = comm_open(SOCK_STREAM, 0, getOutgoingAddr(NULL), 0,
++ COMM_NONBLOCKING, icap->current_service->uri);
++ debug(81, 5) ("icapConnect: new socket, FD %d, local address %s\n",
++ icap->icap_fd, inet_ntoa(getOutgoingAddr(NULL)));
++ if (icap->icap_fd < 0) {
++ icapStateFree(-1, icap); /* XXX test */
++ return 0;
++ }
++ icap->flags.connect_pending = 1;
++ /*
++ * Configure timeout and close handler before calling
++ * connect because commConnectStart() might get an error
++ * immediately and close the descriptor before it returns.
++ */
++ commSetTimeout(icap->icap_fd, Config.Timeout.connect,
++ icapConnectTimeout, icap);
++ comm_add_close_handler(icap->icap_fd, icapStateFree, icap);
++ /*
++ * This sucks. commConnectStart() may fail before returning,
++ * so lets lock the data and check its validity afterwards.
++ */
++ cbdataLock(icap);
++ commConnectStart(icap->icap_fd,
++ icap->current_service->hostname,
++ icap->current_service->port, theCallback, icap);
++ rc = cbdataValid(icap);
++ cbdataUnlock(icap);
++ debug(81, 3) ("icapConnect: returning %d\n", rc);
++ return rc;
++}
++
++IcapStateData *
++icapAllocate(void)
++{
++ IcapStateData *icap;
++
++ if (!Config.icapcfg.onoff)
++ return 0;
++
++ icap = cbdataAlloc(IcapStateData);
++ icap->icap_fd = -1;
++ icap->enc.res_hdr = -1;
++ icap->enc.res_body = -1;
++ icap->enc.req_hdr = -1;
++ icap->enc.req_body = -1;
++ icap->enc.opt_body = -1;
++ icap->enc.null_body = -1;
++ icap->chunk_size = -1;
++ memBufDefInit(&icap->icap_hdr);
++
++ debug(81, 3) ("New ICAP state\n");
++ return icap;
++}
++
++void
++icapStateFree(int fd, void *data)
++{
++ IcapStateData *icap = data;
++ debug(81, 3) ("icapStateFree: FD %d, icap %p\n", fd, icap);
++ assert(icap);
++ assert(-1 == fd || fd == icap->icap_fd);
++ if (icap->respmod.entry) {
++ /*
++ * If we got some error on this side (like ECONNRESET)
++ * we must signal the other side(s) with a storeAbort()
++ * call.
++ */
++ if (icap->respmod.entry->store_status != STORE_OK)
++ storeAbort(icap->respmod.entry);
++ storeUnlockObject(icap->respmod.entry);
++ icap->respmod.entry = NULL;
++ }
++ requestUnlink(icap->request);
++ icap->request = NULL;
++ if (!memBufIsNull(&icap->icap_hdr))
++ memBufClean(&icap->icap_hdr);
++ if (!memBufIsNull(&icap->respmod.buffer))
++ memBufClean(&icap->respmod.buffer);
++ if (!memBufIsNull(&icap->respmod.req_hdr_copy))
++ memBufClean(&icap->respmod.req_hdr_copy);
++ if (!memBufIsNull(&icap->respmod.resp_copy))
++ memBufClean(&icap->respmod.resp_copy);
++ if (!memBufIsNull(&icap->reqmod.hdr_buf))
++ memBufClean(&icap->reqmod.hdr_buf);
++ if (!memBufIsNull(&icap->reqmod.http_entity.buf))
++ memBufClean(&icap->reqmod.http_entity.buf);
++ if (!memBufIsNull(&icap->chunk_buf))
++ memBufClean(&icap->chunk_buf);
++ if (icap->httpState)
++ httpStateFree(-1, icap->httpState);
++ cbdataUnlock(icap->reqmod.client_cookie);
++ cbdataFree(icap);
++}
++
++void
++icapConnectTimeout(int fd, void *data)
++{
++ IcapStateData *icap = data;
++ debug(81, 3) ("icapConnectTimeout: FD %d, unreachable=1\n", fd);
++ assert(fd == icap->icap_fd);
++ icapOptSetUnreachable(icap->current_service);
++ comm_close(fd);
++}
++
++void
++icapReadTimeout(int fd, void *data)
++{
++ IcapStateData *icap = data;
++ assert(fd == icap->icap_fd);
++ if (icap->flags.wait_for_preview_reply || icap->flags.http_server_eof) {
++ debug(81, 3) ("icapReadTimeout: FD %d, unreachable=1\n", fd);
++ icapOptSetUnreachable(icap->current_service);
++ } else
++ debug(81, 3) ("icapReadTimeout: FD %d, still reachable\n", fd);
++ comm_close(fd);
++}
++
++icap_service_t
++icapServiceToType(const char *s)
++{
++ if (!strcmp(s, "reqmod_precache"))
++ return ICAP_SERVICE_REQMOD_PRECACHE;
++ if (!strcmp(s, "reqmod_postcache"))
++ return ICAP_SERVICE_REQMOD_POSTCACHE;
++ if (!strcmp(s, "respmod_precache"))
++ return ICAP_SERVICE_RESPMOD_PRECACHE;
++ if (!strcmp(s, "respmod_postcache"))
++ return ICAP_SERVICE_RESPMOD_POSTCACHE;
++ return ICAP_SERVICE_MAX;
++}
++
++const char *
++icapServiceToStr(const icap_service_t type)
++{
++ if (type >= 0 && type < ICAP_SERVICE_MAX)
++ return icap_service_type_str[type];
++ else
++ return "error";
++}
++
++
++/* copied from clientAclChecklistCreate */
++static aclCheck_t *
++icapAclChecklistCreate(const acl_access * acl, const clientHttpRequest * http)
++{
++ aclCheck_t *ch;
++ ConnStateData *conn = http->conn;
++ ch = aclChecklistCreate(acl, http->request, 0);
++ ch->conn = conn;
++ cbdataLock(ch->conn);
++ return ch;
++}
++
++/*
++ * check wether we do icap for a request
++ */
++int
++icapCheckAcl(clientHttpRequest * http)
++{
++ icap_access *iter;
++ aclCheck_t *icapChecklist;
++
++ for (iter = Config.icapcfg.access_head; iter; iter = iter->next) {
++ acl_access *A = iter->access;
++ icapChecklist = icapAclChecklistCreate(A, http);
++ if (aclMatchAclList(A->acl_list, icapChecklist)) {
++ debug(81, 5) ("icapCheckAcl: match for class=%s\n",
++ iter->class->name);
++ if (A->allow) {
++ /* allow rule, do icap and use associated class */
++ http->request->class = iter->class;
++ aclChecklistFree(icapChecklist);
++ return 1;
++ } else {
++ /* deny rule, stop processing */
++ aclChecklistFree(icapChecklist);
++ return 0;
++ }
++ }
++ aclChecklistFree(icapChecklist);
++ }
++ return 0;
++}
++
++/* icapLineLength
++ *
++ * returns the amount of data until lineending ( \r\n )
++ * This function is NOT tolerant of variations of \r\n.
++ */
++size_t
++icapLineLength(const char *start, int len)
++{
++ size_t lineLen = 0;
++ char *end = (char *) memchr(start, '\r', len);
++ if (NULL == end)
++ return 0;
++ end++; /* advance to where '\n' should be */
++ lineLen = end - start + 1;
++ if (lineLen > len) {
++ debug(0, 0) ("icapLineLength: warning lineLen (%d) > len (%d)\n",
++ lineLen, len);
++ return 0;
++ }
++ if (*end != '\n') {
++ debug(0, 0) ("icapLineLength: warning *end (%x) != '\\n'\n", *end);
++ return 0;
++ }
++ debug(81, 7) ("icapLineLength: returning %d\n", lineLen);
++ return lineLen;
++}
++
++/*
++ * return:
++ * -1 if EOF before getting end of ICAP header
++ * 0 if we don't have the entire ICAP header yet
++ * 1 if we got the whole header
++ */
++int
++icapReadHeader(int fd, IcapStateData * icap, int *isIcap)
++{
++ int headlen = 0;
++ int len = 0;
++ int peek_sz = EXPECTED_ICAP_HEADER_LEN;
++ int read_sz = 0;
++ LOCAL_ARRAY(char, tmpbuf, SQUID_TCP_SO_RCVBUF);
++ for (;;) {
++ len = recv(fd, tmpbuf, peek_sz, MSG_PEEK);
++ debug(81, 5) ("recv(FD %d, ..., MSG_PEEK) ret %d\n", fd, len);
++ if (len < 0) {
++ debug(81, 1) ("icapReadHeader: FD %d recv error: %s\n", fd,
++ xstrerror());
++ return -1;
++ }
++ if (len == 0) {
++ debug(81, 2) ("icapReadHeader: FD %d recv EOF\n", fd);
++ return -1;
++ }
++ headlen = headersEnd(tmpbuf, len);
++ debug(81, 3) ("headlen=%d\n", headlen);
++ /*
++ * break if we now know where the ICAP headers end
++ */
++ if (headlen)
++ break;
++ /*
++ * break if we know there is no more data to read
++ */
++ if (len < peek_sz)
++ break;
++ /*
++ * The ICAP header is larger than (or equal to) our read
++ * buffer, so double it and try to peek again.
++ */
++ peek_sz *= 2;
++ if (peek_sz >= SQUID_TCP_SO_RCVBUF) {
++ debug(81,
++ 1) ("icapReadHeader: Failed to find end of ICAP header\n");
++ debug(81, 1) ("\twithin first %d bytes of response\n",
++ SQUID_TCP_SO_RCVBUF);
++ debug(81, 1) ("\tpossible persistent connection bug/confusion\n");
++ return -1;
++ }
++ }
++ /*
++ * Now actually read the data from the kernel
++ */
++ if (headlen)
++ read_sz = headlen;
++ else
++ read_sz = len;
++ len = FD_READ_METHOD(fd, tmpbuf, read_sz);
++ assert(len == read_sz);
++ fd_bytes(fd, len, FD_READ);
++ memBufAppend(&icap->icap_hdr, tmpbuf, len);
++ if (headlen) {
++ /* End of ICAP header found */
++ if (icap->icap_hdr.size < 4)
++ *isIcap = 0;
++ else if (0 == strncmp(icap->icap_hdr.buf, "ICAP", 4))
++ *isIcap = 1;
++ else
++ *isIcap = 0;
++ return 1;
++ }
++ /*
++ * We don't have all the headers yet
++ */
++ return 0;
++}
++
++static int
++icapParseConnectionClose(const IcapStateData * icap, const char *s,
++ const char *e)
++{
++ char *t;
++ char *q;
++ /*
++ * s points to the start of the line "Connection: ... "
++ * e points to *after* the last character on the line
++ */
++ s += 11; /* skip past Connection: */
++ while (s < e && isspace(*s))
++ s++;
++ if (e - s < 5)
++ return 0;
++ /*
++ * create a buffer that we can use strtok on
++ */
++ t = xmalloc(e - s + 1);
++ strncpy(t, s, e - s);
++ *(t + (e - s)) = '\0';
++ for (q = strtok(t, ","); q; q = strtok(NULL, ",")) {
++ if (0 == strcasecmp(q, "close")) {
++ xfree(t);
++ return 1;
++ }
++ }
++ xfree(t);
++ return 0;
++}
++
++/* returns icap status, version and subversion extracted from status line or -1 on parsing failure
++ * The str_status pointr points to the text returned from the icap server.
++ * sline probably is NOT terminated with '\0'
++ */
++int
++icapParseStatusLine(const char *sline, int slinesize, int *version_major,
++ int *version_minor, const char **str_status)
++{
++ char *sp, *stmp, *ep = (char *) sline + slinesize;
++ int status;
++ if (slinesize < 14) /*The format of this line is: "ICAP/x.x xxx[ msg....]\r\n" */
++ return -1;
++
++ if (strncmp(sline, "ICAP/", 5) != 0)
++ return -1;
++ if (sscanf(sline + 5, "%d.%d", version_major, version_minor) != 2)
++ return -1;
++
++ if (!(sp = memchr(sline, ' ', slinesize)))
++ return -1;
++
++ while (sp < ep && xisspace(*++sp));
++
++ if (!xisdigit(*sp) || sp >= ep)
++ return -1;
++
++ if ((status = strtol(sp, &stmp, 10)) <= 0)
++ return -1;
++ sp = stmp;
++
++ while (sp < ep && xisspace(*++sp));
++ *str_status = sp;
++ /*Must add a test for "\r\n" end headers .... */
++ return status;
++}
++
++
++void
++icapSetKeepAlive(IcapStateData * icap, const char *hdrs)
++{
++ const char *start;
++ const char *end;
++ if (0 == icap->flags.keep_alive)
++ return;
++ if (0 == icapFindHeader(hdrs, "Connection:", &start, &end)) {
++ icap->flags.keep_alive = 1;
++ return;
++ }
++ if (icapParseConnectionClose(icap, start, end))
++ icap->flags.keep_alive = 0;
++ else
++ icap->flags.keep_alive = 1;
++}
++
++/*
++ * icapParseChunkSize
++ *
++ * Returns the offset where the next chunk starts
++ * return parameter chunk_size;
++ */
++static int
++icapParseChunkSize(const char *buf, int len, int *chunk_size)
++{
++ int chunkSize = 0;
++ char c;
++ size_t start;
++ size_t end;
++ size_t nextStart = 0;
++ debug(81, 3) ("icapParseChunkSize: buf=%p, len=%d\n", buf, len);
++ do {
++ start = nextStart;
++ debug(81, 3) ("icapParseChunkSize: start=%d\n", start);
++ if (len <= start) {
++ /*
++ * end of buffer, so far no lines or only empty lines,
++ * wait for more data. read chunk size with next buffer.
++ */
++ *chunk_size = 0;
++ return 0;
++ }
++ end = start + icapLineLength(buf + start, len - start);
++ nextStart = end;
++ if (end <= start) {
++ /*
++ * no line found, need more code here, now we are in
++ * deep trouble, buffer stops with half a chunk size
++ * line. For now stop here.
++ */
++ debug(81, 1) ("icapParseChunkSize: WARNING in mid-line, ret 0\n");
++ *chunk_size = 0;
++ return 0;
++ }
++ while (start < end) {
++ if (NULL == strchr(w_space, buf[start]))
++ break;
++ start++;
++ }
++ while (start < end) {
++ if (NULL == strchr(w_space, buf[end - 1]))
++ break;
++ end--;
++ }
++ /*
++ * if now end <= start we got an empty line. The previous
++ * chunk data should stop with a CRLF. In case that the
++ * other end does not follow the specs and sends no CRLF
++ * or too many empty lines, just continue till we have a
++ * non-empty line.
++ */
++ } while (end <= start);
++ debug(81, 3) ("icapParseChunkSize: start=%d, end=%d\n", start, end);
++
++ /* Non-empty line: Parse the chunk size */
++ while (start < end) {
++ c = buf[start++];
++ if (c >= 'a' && c <= 'f') {
++ chunkSize = chunkSize * 16 + c - 'a' + 10;
++ } else if (c >= 'A' && c <= 'F') {
++ chunkSize = chunkSize * 16 + c - 'A' + 10;
++ } else if (c >= '0' && c <= '9') {
++ chunkSize = chunkSize * 16 + c - '0';
++ } else {
++ if (!(c == ';' || c == ' ' || c == '\t')) {
++ /*Syntax error: Chunksize expected. */
++ *chunk_size = -2; /* we are done */
++ return nextStart;
++ }
++ /* Next comes a chunk extension */
++ break;
++ }
++ }
++ /*
++ * if we read a zero chunk, we reached the end. Mark this for
++ * icapPconnTransferDone
++ */
++ *chunk_size = (chunkSize > 0) ? chunkSize : -2;
++ debug(81, 3) ("icapParseChunkSize: return nextStart=%d\n", nextStart);
++ return nextStart;
++}
++
++/*
++ * icapParseChunkedBody
++ *
++ * De-chunk an HTTP entity received from the ICAP server.
++ * The 'store' function pointer is storeAppend() or memBufAppend().
++ */
++size_t
++icapParseChunkedBody(IcapStateData * icap, STRCB * store, void *store_data)
++{
++ int bufOffset = 0;
++ size_t bw = 0;
++ MemBuf *cb = &icap->chunk_buf;
++ const char *buf = cb->buf;
++ int len = cb->size;
++
++ if (icap->chunk_size == -2) {
++ debug(81, 3) ("zero end chunk reached\n");
++ return 0;
++ }
++ debug(81, 3) ("%s:%d: chunk_size=%d\n", __FILE__, __LINE__,
++ icap->chunk_size);
++ if (icap->chunk_size < 0) {
++ store(store_data, buf, len);
++ cb->size = 0;
++ return (size_t) len;
++ }
++ debug(81, 3) ("%s:%d: bufOffset=%d, len=%d\n", __FILE__, __LINE__,
++ bufOffset, len);
++ while (bufOffset < len) {
++ debug(81, 3) ("%s:%d: bufOffset=%d, len=%d\n", __FILE__, __LINE__,
++ bufOffset, len);
++ if (icap->chunk_size == 0) {
++ int x;
++ x = icapParseChunkSize(buf + bufOffset,
++ len - bufOffset, &icap->chunk_size);
++ if (x < 1) {
++ /* didn't find a valid chunk spec */
++ break;
++ }
++ bufOffset += x;
++ debug(81, 3) ("got chunksize %d, new offset %d\n",
++ icap->chunk_size, bufOffset);
++ if (icap->chunk_size == -2) {
++ debug(81, 3) ("zero end chunk reached\n");
++ break;
++ }
++ }
++ debug(81, 3) ("%s:%d: X\n", __FILE__, __LINE__);
++ if (icap->chunk_size > 0) {
++ if (icap->chunk_size >= len - bufOffset) {
++ store(store_data, buf + bufOffset, len - bufOffset);
++ bw += (len - bufOffset);
++ icap->chunk_size -= (len - bufOffset);
++ bufOffset = len;
++ } else {
++ store(store_data, buf + bufOffset, icap->chunk_size);
++ bufOffset += icap->chunk_size;
++ bw += icap->chunk_size;
++ icap->chunk_size = 0;
++ }
++ }
++ }
++ if (0 == bufOffset) {
++ (void) 0;
++ } else if (bufOffset == cb->size) {
++ cb->size = 0;
++ } else {
++ assert(bufOffset <= cb->size);
++ xmemmove(cb->buf, cb->buf + bufOffset, cb->size - bufOffset);
++ cb->size -= bufOffset;
++ }
++ return bw;
++}
++
++/*
++ * icapAddAuthUserHeader
++ *
++ * Builds and adds the X-Authenticated-User header to an ICAP request headers.
++ */
++void
++icapAddAuthUserHeader(MemBuf * mb, auth_user_request_t * auth_user_request)
++{
++ char *user = authenticateUserRequestUsername(auth_user_request);
++ char *authuser;
++ size_t len, userlen, schemelen, userofslen;
++ char *userofs;
++
++ if (user == NULL) {
++ debug(81, 5) ("icapAddAuthUserHeader: NULL username\n");
++ return;
++ }
++ userlen = strlen(user);
++ schemelen = strlen(Config.icapcfg.auth_scheme);
++ len = userlen + schemelen + 1;
++ authuser = xcalloc(len, 1);
++
++ if ((userofs = strstr(Config.icapcfg.auth_scheme, "%u")) == NULL) {
++ /* simply add user at end of string */
++ snprintf(authuser, len, "%s%s", Config.icapcfg.auth_scheme, user);
++ } else {
++ userofslen = userofs - Config.icapcfg.auth_scheme;
++ xmemcpy(authuser, Config.icapcfg.auth_scheme, userofslen);
++ xmemcpy(authuser + userofslen, user, userlen);
++ xmemcpy(authuser + userofslen + userlen,
++ userofs + 2, schemelen - (userofslen + 2) + 1);
++ }
++
++ memBufPrintf(mb, "X-Authenticated-User: %s\r\n", base64_encode(authuser));
++ xfree(authuser);
++}
++
++/*
++ * icapAddOriginIP
++ *
++ * Builds and adds the X-Server-IP header to an ICAP request headers.
++ */
++void
++icapAddOriginIP(MemBuf * mb, const char *host)
++{
++ const ipcache_addrs *addrs;
++ struct in_addr s;
++
++ if (host == NULL) {
++ debug(81, 5) ("icapAddOriginIP: NULL host\n");
++ return;
++ }
++ addrs = ipcache_gethostbyname(host, IP_LOOKUP_IF_MISS);
++ if (addrs == NULL) {
++ /*
++ * http://www.i-cap.org/spec/draft-stecher-icap-subid-00.txt :
++ *
++ * [...] If the meta information for some header is not available,
++ * the header field MUST be omitted.
++ */
++ debug(81, 5) ("icapAddOriginIP: can't tell IP address\n");
++ return;
++ }
++ s = addrs->in_addrs[0];
++ memBufPrintf(mb, "X-Server-IP: %s\r\n", inet_ntoa(s));
++}
+Index: src/icap_opt.c
+===================================================================
+RCS file: src/icap_opt.c
+diff -N src/icap_opt.c
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ src/icap_opt.c 17 May 2006 17:58:01 -0000 1.1.16.1
+@@ -0,0 +1,523 @@
++
++/*
++ * $Id$
++ *
++ * DEBUG: section 81 Internet Content Adaptation Protocol (ICAP) Client OPTIONS
++ * AUTHOR: Ralf Horstmann
++ *
++ * 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"
++
++/*************************************************************/
++
++/*
++ * network related functions for OPTIONS request
++ */
++static void icapOptStart(void *data);
++static void icapOptTimeout(int fd, void *data);
++static void icapOptConnectDone(int server_fd, int status, void *data);
++static void icapOptWriteComplete(int fd, char *bufnotused, size_t size, int errflag, void *data);
++static void icapOptReadReply(int fd, void *data);
++
++/*
++ * reply parsing functions
++ */
++static int icapOptParseReply(icap_service * s, IcapOptData * i);
++static void icapOptParseEntry(icap_service * s, const char *blk_start, const char *blk_end);
++static int icapIsolateLine(const char **parse_start, const char **blk_start, const char **blk_end);
++
++/*
++ * helper functions
++ */
++static void icapOptDataInit(IcapOptData * i);
++static void icapOptDataFree(IcapOptData * i);
++
++/*************************************************************/
++
++#define TIMEOUT 10
++
++void
++icapOptInit()
++{
++ icap_service *s;
++
++ /* iterate over configured services */
++ s = Config.icapcfg.service_head;
++ while (s) {
++ eventAdd("icapOptStart", icapOptStart, s, 5.0, 1);
++ s = s->next;
++ }
++}
++
++void
++icapOptShutdown()
++{
++ icap_service *s;
++
++ s = Config.icapcfg.service_head;
++ while (s) {
++ if (eventFind(icapOptStart, s)) {
++ eventDelete(icapOptStart, s);
++ }
++ s = s->next;
++ }
++}
++
++/*
++ * mark a service as unreachable
++ */
++void
++icapOptSetUnreachable(icap_service * s)
++{
++ s->unreachable = 1;
++ debug(81, 5) ("icapOptSetUnreachable: got called for %s\n", s->uri);
++ /*
++ * if there is an options request scheduled, delete it and add
++ * it again to reset the time to the default check_interval.
++ */
++ if (eventFind(icapOptStart, s)) {
++ eventDelete(icapOptStart, s);
++ eventAdd("icapOptStart", icapOptStart, s, Config.icapcfg.check_interval, 1);
++ }
++}
++
++static void
++icapOptStart(void *data)
++{
++ icap_service *s = data;
++ int fd;
++ int ctimeout = TIMEOUT;
++ const char *host = s->hostname;
++ unsigned short port = s->port;
++ debug(81, 3) ("icapOptStart: starting OPTIONS request for %s (%s)\n", s->name, s->uri);
++ fd = comm_open(SOCK_STREAM,
++ 0,
++ getOutgoingAddr(NULL),
++ 0,
++ COMM_NONBLOCKING,
++ "ICAP OPTIONS connection");
++ if (fd < 0) {
++ debug(81, 4) ("icapConnectStart: %s\n", xstrerror());
++ eventAdd("icapOptStart", icapOptStart, s, Config.icapcfg.check_interval, 1);
++ return;
++ }
++ assert(s->opt == NULL); /* if not null, another options request might be running, which should not happen */
++ s->opt = memAllocate(MEM_ICAP_OPT_DATA);
++ icapOptDataInit(s->opt);
++ cbdataLock(s);
++ commSetTimeout(fd, ctimeout, icapOptTimeout, s);
++ commConnectStart(fd, host, port, icapOptConnectDone, s);
++}
++
++static void
++icapOptTimeout(int fd, void *data)
++{
++ icap_service *s = data;
++ IcapOptData *i = s->opt;
++ int valid;
++
++ debug(81, 4) ("icapOptConnectTimeout: fd=%d, service=%s\n", fd, s->uri);
++
++ comm_close(fd);
++ valid = cbdataValid(s);
++ cbdataUnlock(s);
++ if (!valid) {
++ icapOptDataFree(i);
++ s->opt = NULL;
++ return;
++ }
++ /* try again later */
++ icapOptDataFree(i);
++ s->opt = NULL;
++ s->unreachable = 1;
++ debug(81, 3) ("icapOptConnectTimeout: unreachable=1, service=%s\n", s->uri);
++ eventAdd("icapOptStart", icapOptStart, s, Config.icapcfg.check_interval, 1);
++
++}
++
++static void
++icapOptConnectDone(int server_fd, int status, void *data)
++{
++ icap_service *s = data;
++ IcapOptData *i = s->opt;
++ MemBuf request;
++ int valid;
++
++ valid = cbdataValid(s);
++ cbdataUnlock(s);
++ if (!valid) {
++ comm_close(server_fd);
++ icapOptDataFree(i);
++ s->opt = NULL;
++ return;
++ }
++ if (status != COMM_OK) {
++ debug(81, 3) ("icapOptConnectDone: unreachable=1, service=%s\n", s->uri);
++ comm_close(server_fd);
++ icapOptDataFree(i);
++ s->opt = NULL;
++ s->unreachable = 1;
++ eventAdd("icapOptStart", icapOptStart, s, Config.icapcfg.check_interval, 1);
++ return;
++ }
++ debug(81, 3) ("icapOptConnectDone: Connection ok. Sending Options request for %s\n", s->name);
++ memBufDefInit(&request);
++ memBufPrintf(&request, "OPTIONS %s ICAP/1.0\r\n", s->uri);
++ memBufPrintf(&request, "Host: %s\r\n", s->hostname);
++ memBufPrintf(&request, "Connection: close\r\n");
++ memBufPrintf(&request, "User-Agent: ICAP-Client-Squid/1.2\r\n");
++ memBufPrintf(&request, "\r\n");
++ cbdataLock(s);
++ commSetTimeout(server_fd, TIMEOUT, icapOptTimeout, s);
++ comm_write_mbuf(server_fd, request, icapOptWriteComplete, s);
++}
++
++static void
++icapOptWriteComplete(int fd, char *bufnotused, size_t size, int errflag, void *data)
++{
++ icap_service *s = data;
++ IcapOptData *i = s->opt;
++ int valid;
++
++ valid = cbdataValid(s);
++ cbdataUnlock(s);
++ if (!valid) {
++ comm_close(fd);
++ icapOptDataFree(i);
++ s->opt = NULL;
++ return;
++ }
++ debug(81, 5) ("icapOptWriteComplete: FD %d: size %d: errflag %d.\n",
++ fd, size, errflag);
++ if (size > 0) {
++ fd_bytes(fd, size, FD_WRITE);
++ kb_incr(&statCounter.icap.all.kbytes_out, size);
++ }
++ if (errflag) {
++ /* cancel this for now */
++ debug(81, 3) ("icapOptWriteComplete: unreachable=1, service=%s\n", s->uri);
++ icapOptDataFree(i);
++ s->opt = NULL;
++ s->unreachable = 1;
++ eventAdd("icapOptStart", icapOptStart, s, Config.icapcfg.check_interval, 1);
++ comm_close(fd);
++ return;
++ }
++ cbdataLock(s);
++ commSetSelect(fd, COMM_SELECT_READ, icapOptReadReply, s, 0);
++}
++
++static void
++icapOptReadReply(int fd, void *data)
++{
++ icap_service *s = data;
++ IcapOptData *i = s->opt;
++ int size;
++ int len = i->size - i->offset - 1;
++ int valid;
++
++ valid = cbdataValid(s);
++ cbdataUnlock(s);
++ if (!valid) {
++ comm_close(fd);
++ icapOptDataFree(i);
++ s->opt = NULL;
++ return;
++ }
++ if (len == 0) {
++ /* Grow the request memory area to accomodate for a large request */
++ printf("PANIC: not enough memory\n");
++#if 0
++ i->buf = memReallocBuf(i->buf, i->size * 2, &i->size);
++ debug(81, 2) ("icapoptReadReply: growing reply buffer: offset=%ld size=%ld\n",
++ (long) i->offset, (long) i->size);
++ len = i->size - i->offset - 1;
++#endif
++ }
++ size = FD_READ_METHOD(fd, i->buf + i->offset, len);
++ i->offset += size;
++ debug(81, 3) ("icapOptReadReply: Got %d bytes of data\n", size);
++ if (size > 0) {
++ /* do some statistics */
++ fd_bytes(fd, size, FD_READ);
++ kb_incr(&statCounter.icap.all.kbytes_in, size);
++
++ /*
++ * some icap servers seem to ignore the "Connection: close" header. so
++ * after getting the complete option reply we close the connection
++ * ourself.
++ */
++ if ((i->headlen = headersEnd(i->buf, i->offset))) {
++ debug(81, 3) ("icapOptReadReply: EndOfResponse\n");
++ size = 0;
++ }
++ }
++ if (size < 0) {
++ debug(81, 3) ("icapOptReadReply: FD %d: read failure: %s.\n", fd, xstrerror());
++ debug(81, 3) ("icapOptReadReply: unreachable=1, service=%s.\n", s->uri);
++ s->unreachable = 1;
++ icapOptDataFree(i);
++ s->opt = NULL;
++ eventAdd("icapOptStart", icapOptStart, s, Config.icapcfg.check_interval, 1);
++ comm_close(fd);
++ } else if (size == 0) {
++ /* no more data, now we can parse the reply */
++ debug(81, 3) ("icapOptReadReply: FD %d: connection closed\n", fd);
++ i->buf[i->offset] = '\0'; /* for string functions */
++ debug(81, 3) ("icapOptReadReply: unreachable=0, service=%s\n", s->uri);
++
++ if (!icapOptParseReply(s, i)) {
++ debug(81, 3) ("icapOptReadReply: OPTIONS request not successful. scheduling again in %d seconds\n", Config.icapcfg.check_interval);
++ s->unreachable = 1;
++ } else
++ s->unreachable = 0;
++
++ if (s->options_ttl <= 0)
++ s->options_ttl = Config.icapcfg.check_interval;
++ eventAdd("icapOptStart", icapOptStart, s, s->options_ttl, 1);
++
++ icapOptDataFree(i);
++ s->opt = NULL;
++ comm_close(fd);
++ } else {
++ /* data received */
++ /* commSetSelect(fd, Type, handler, client_data, timeout) */
++ cbdataLock(s);
++ commSetSelect(fd, COMM_SELECT_READ, icapOptReadReply, data, 0);
++ }
++}
++
++static int
++icapIsolateLine(const char **parse_start, const char **blk_start, const char **blk_end)
++{
++ int slen = strcspn(*parse_start, "\r\n");
++
++ if (!(*parse_start)[slen]) /* no crlf */
++ return 0;
++
++ if (slen == 0) /* empty line */
++ return 0;
++
++ *blk_start = *parse_start;
++ *blk_end = *blk_start + slen;
++
++ /* set it to the beginning of next line */
++ *parse_start = *blk_end;
++ while (**parse_start == '\r') /* CR */
++ (*parse_start)++;
++ if (**parse_start == '\n') /* LF */
++ (*parse_start)++;
++ return 1;
++}
++
++/* process a single header entry between blk_start and blk_end */
++static void
++icapOptParseEntry(icap_service * s, const char *blk_start, const char *blk_end)
++{
++ const char *name_end = strchr(blk_start, ':');
++ const int name_len = name_end ? name_end - blk_start : 0;
++ const char *value_start = blk_start + name_len + 1; /* skip ':' */
++ int value_len;
++ int new;
++
++ if (!name_len || name_end > blk_end) {
++ debug(81, 5) ("icapOptParseEntry: strange header. skipping\n");
++ return;
++ }
++ if (name_len > 65536) {
++ debug(81, 5) ("icapOptParseEntry: unusual long header item. skipping.\n");
++ return;
++ }
++ while (xisspace(*value_start) && value_start < blk_end) {
++ value_start++;
++ }
++ if (value_start >= blk_end) {
++ debug(81, 5) ("icapOptParseEntry: no value found\n");
++ return;
++ }
++ value_len = blk_end - value_start;
++
++
++ /* extract information */
++ if (!strncasecmp("Allow", blk_start, name_len)) {
++ debug(81, 5) ("icapOptParseEntry: found Allow\n");
++ if (!strncmp("204", value_start, 3)) {
++ s->flags.allow_204 = 1;
++ } else {
++ debug(81, 3) ("icapOptParseEntry: Allow value unknown");
++ }
++ } else if (!strncasecmp("Connection", blk_start, name_len)) {
++ debug(81, 5) ("icapOptParseEntry: found Connection\n");
++ } else if (!strncasecmp("Encapsulated", blk_start, name_len)) {
++ debug(81, 5) ("icapOptParseEntry: found Encapsulated\n");
++ } else if (!strncasecmp("ISTAG", blk_start, name_len)) {
++ debug(81, 5) ("icapOptParseEntry: found ISTAG\n");
++ stringClean(&s->istag);
++ stringLimitInit(&s->istag, value_start, value_len);
++ } else if (!strncasecmp("Max-Connections", blk_start, name_len)) {
++ debug(81, 5) ("icapOptParseEntry: found Max-Connections\n");
++ errno = 0;
++ new = strtol(value_start, NULL, 10);
++ if (errno) {
++ debug(81, 5) ("icapOptParseEntry: Max-Connections: could not parse value\n");
++ } else {
++ debug(81, 5) ("icapOptParseEntry: Max-Connections: new value=%d\n", new);
++ s->max_connections = new;
++ }
++ } else if (!strncasecmp("Methods", blk_start, name_len)) {
++ debug(81, 5) ("icapOptParseEntry: found Methods\n");
++ } else if (!strncasecmp("Options-TTL", blk_start, name_len)) {
++ debug(81, 5) ("icapOptParseEntry: found Options-TTL\n");
++ errno = 0;
++ new = strtol(value_start, NULL, 10);
++ if (errno) {
++ debug(81, 5) ("icapOptParseEntry: Options-TTL: could not parse value\n");
++ } else {
++ debug(81, 5) ("icapOptParseEntry: Options-TTL: new value=%d\n", new);
++ s->options_ttl = new;
++ }
++ } else if (!strncasecmp("Preview", blk_start, name_len)) {
++ debug(81, 5) ("icapOptParseEntry: found Preview\n");
++ errno = 0;
++ new = strtol(value_start, NULL, 10);
++ if (errno) {
++ debug(81, 5) ("icapOptParseEntry: Preview: could not parse value\n");
++ } else {
++ debug(81, 5) ("icapOptParseEntry: Preview: new value=%d\n", new);
++ s->preview = new;
++ }
++ } else if (!strncasecmp("Service", blk_start, name_len)) {
++ debug(81, 5) ("icapOptParseEntry: found Service\n");
++ } else if (!strncasecmp("Service-ID", blk_start, name_len)) {
++ debug(81, 5) ("icapOptParseEntry: found Service-ID\n");
++ } else if (!strncasecmp("Transfer-Preview", blk_start, name_len)) {
++ debug(81, 5) ("icapOptParseEntry: found Transfer-Preview\n");
++ stringClean(&s->transfer_preview);
++ stringLimitInit(&s->transfer_preview, value_start, value_len);
++ } else if (!strncasecmp("Transfer-Ignore", blk_start, name_len)) {
++ debug(81, 5) ("icapOptParseEntry: found Transfer-Ignore\n");
++ stringClean(&s->transfer_ignore);
++ stringLimitInit(&s->transfer_ignore, value_start, value_len);
++ } else if (!strncasecmp("Transfer-Complete", blk_start, name_len)) {
++ debug(81, 5) ("icapOptParseEntry: found Transfer-Complete\n");
++ stringClean(&s->transfer_complete);
++ stringLimitInit(&s->transfer_complete, value_start, value_len);
++ } else if (!strncasecmp("X-Include", blk_start, name_len)) {
++ debug(81, 5) ("icapOptParseEntry: found X-Include\n");
++ if (strstr(value_start, "X-Client-IP")) {
++ debug(81, 5) ("icapOptParseEntry: X-Include: found X-Client-IP\n");
++ s->flags.need_x_client_ip = 1;
++ }
++ if (strstr(value_start, "X-Server-IP")) {
++ debug(81, 5) ("icapOptParseEntry: X-Include: found X-Server-IP\n");
++ s->flags.need_x_server_ip = 1;
++ }
++ if (strstr(value_start, "X-Authenticated-User")) {
++ debug(81, 5) ("icapOptParseEntry: X-Include: found X-Authenticated-User\n");
++ s->flags.need_x_authenticated_user = 1;
++ }
++ } else {
++ debug(81, 5) ("icapOptParseEntry: unknown options header\n");
++ }
++}
++
++/* parse OPTIONS reply */
++static int
++icapOptParseReply(icap_service * s, IcapOptData * i)
++{
++ int version_major, version_minor;
++ const char *str_status;
++ int status;
++ const char *buf = i->buf;
++ const char *parse_start;
++ const char *head_end;
++ const char *blk_start;
++ const char *blk_end;
++
++ if ((status =
++ icapParseStatusLine(i->buf, i->offset,
++ &version_major, &version_minor, &str_status)) < 0) {
++ debug(81, 2) ("icapOptParseReply: bad status line <%s>\n", i->buf);
++ return 0;
++ }
++ debug(81, 3) ("icapOptParseReply: got reply: <ICAP/%d.%d %d %s>\n", version_major, version_minor, status, str_status);
++
++ if (status != 200) {
++ debug(81, 3) ("icapOptParseReply: status = %d != 200\n", status);
++ return 0;
++ }
++ parse_start = buf;
++ if (i->headlen == 0)
++ i->headlen = headersEnd(parse_start, s->opt->offset);
++
++ if (!i->headlen) {
++ debug(81, 2) ("icapOptParseReply: end of headers could not be found\n");
++ return 0;
++ }
++ head_end = parse_start + i->headlen - 1;
++ while (*(head_end - 1) == '\r')
++ head_end--;
++ assert(*(head_end - 1) == '\n');
++ if (*head_end != '\r' && *head_end != '\n')
++ return 0; /* failure */
++
++ /* skip status line */
++ if (!icapIsolateLine(&parse_start, &blk_start, &blk_end)) {
++ debug(81, 3) ("icapOptParseReply: failure in isolating status line\n");
++ return 0;
++
++ }
++ /* now we might start real parsing */
++ while (icapIsolateLine(&parse_start, &blk_start, &blk_end)) {
++ if (blk_end > head_end || blk_start > head_end || blk_start >= blk_end) {
++ debug(81, 3) ("icapOptParseReply: header limit exceeded. finished.\n");
++ break;
++ }
++ icapOptParseEntry(s, blk_start, blk_end);
++ }
++ return 1;
++}
++
++static void
++icapOptDataInit(IcapOptData * i)
++{
++ i->buf = memAllocBuf(HTTP_REPLY_BUF_SZ, &i->size);
++ i->offset = 0;
++ i->headlen = 0;
++}
++
++static void
++icapOptDataFree(IcapOptData * i)
++{
++ if (i) {
++ memFreeBuf(i->size, i->buf);
++ memFree(i, MEM_ICAP_OPT_DATA);
++ }
++}
+Index: src/icap_reqmod.c
+===================================================================
+RCS file: src/icap_reqmod.c
+diff -N src/icap_reqmod.c
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ src/icap_reqmod.c 13 Jun 2006 17:14:53 -0000 1.1.14.6
+@@ -0,0 +1,992 @@
++
++/*
++ * $Id$
++ *
++ * DEBUG: section 81 Internet Content Adaptation Protocol (ICAP) Client
++ * AUTHOR: Geetha Manjunath, Hewlett Packard Company
++ *
++ * 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"
++
++#define ICAP_PROXY_KEEP_ALIVE 0
++
++/*
++ * These once-static functions are required to be global for ICAP
++ */
++
++PF clientReadRequest;
++PF connStateFree;
++int clientReadDefer(int fd, void *data);
++int clientCheckContentLength(request_t * r);
++void clientProcessRequest(clientHttpRequest *);
++int clientCachable(clientHttpRequest *);
++int clientHierarchical(clientHttpRequest *);
++void clientReadBody(request_t * request, char *buf, size_t size,
++ CBCB * callback, void *cbdata);
++static void icapReqModPassHttpBody(IcapStateData * icap, char *buf, size_t size,
++ CBCB * callback, void *cbdata);
++
++static PF icapReqModReadHttpHdrs;
++static PF icapReqModReadHttpBody;
++static CWCB icapReqModSendBodyChunk;
++static CBCB icapReqModBodyHandler;
++static BODY_HANDLER icapReqModBodyReader;
++static STRCB icapReqModMemBufAppend;
++
++#define EXPECTED_ICAP_HEADER_LEN 256
++static const char *crlf = "\r\n";
++
++/*
++ * icapExpectedHttpReqHdrSize
++ *
++ * calculate the size of the HTTP headers that we expect
++ * to read from the ICAP server.
++ */
++static int
++icapExpectedHttpReqHdrSize(IcapStateData * icap)
++{
++ if (icap->enc.req_body > -1 && icap->enc.req_hdr > -1)
++ return (icap->enc.req_body - icap->enc.req_hdr);
++ if (icap->enc.null_body > -1)
++ return icap->enc.null_body;
++ fatal("icapExpectedHttpReqHdrSize: unexpected case");
++ return 0;
++}
++
++/*
++ * icapReqModCreateClientState
++ *
++ * Creates fake client_side data structures so we can use
++ * that module to read/parse the HTTP request that we read
++ * from the ICAP server.
++ */
++static clientHttpRequest *
++icapReqModCreateClientState(IcapStateData * icap, request_t * request)
++{
++ clientHttpRequest *http;
++ if (!cbdataValid(icap->reqmod.client_cookie)) {
++ debug(81, 3) ("Whups, client cookie invalid\n");
++ icap->reqmod.client_fd = -1;
++ return NULL;
++ }
++ http = cbdataAlloc(clientHttpRequest);
++ /*
++ * use our own urlCanonicalClean here, because urlCanonicalClean
++ * may strip everything after a question-mark. As http->uri
++ * is used when doing a request to a parent proxy, we need the full
++ * url here.
++ */
++ http->uri = xstrdup(urlCanonical(icap->request));
++ http->log_uri = xstrndup(http->uri, MAX_URL);
++ http->range_iter.boundary = StringNull;
++ http->request = requestLink(request ? request : icap->request);
++ http->flags.did_icap_reqmod = 1;
++ http->start = icap->reqmod.start;
++ if (request)
++ http->http_ver = request->http_ver;
++#if ICAP_PROXY_KEEP_ALIVE
++ /*
++ * Here it is possible becouse we are using as client_cookie the original http->conn
++ * if we will keep this code we must declare an icap->conn field........
++ * Will work if pipeline_prefetch is not enabled
++ * We are using a dummy ConnStateData structure, just to free
++ * old clientHttpRequest :-(
++ * OK,all this code is a hack and possibly must not exists in cvs ......
++ */
++
++ http->conn = icap->reqmod.client_cookie;
++ assert(http->conn->chr->next == NULL);
++ {
++ ConnStateData *dummyconn;
++ dummyconn = cbdataAlloc(ConnStateData);
++ dummyconn->fd = icap->reqmod.client_fd;
++ dummyconn->pinning.fd = -1;
++ dummyconn->chr = http->conn->chr;
++ dummyconn->chr->conn = dummyconn;
++ comm_add_close_handler(dummyconn->fd, connStateFree, dummyconn);
++ }
++ http->conn->chr = http;
++#else
++ http->conn = cbdataAlloc(ConnStateData);
++ http->conn->fd = icap->reqmod.client_fd;
++ http->conn->pinning.fd = -1;
++ http->conn->in.size = 0;
++ http->conn->in.buf = NULL;
++ http->conn->log_addr = icap->reqmod.log_addr;
++ http->conn->chr = http;
++ comm_add_close_handler(http->conn->fd, connStateFree, http->conn);
++#endif
++ http->icap_reqmod = NULL;
++ return http;
++}
++
++/*
++ * icapReqModInterpretHttpRequest
++ *
++ * Interpret an HTTP request that we read from the ICAP server.
++ * Create some "fake" clientHttpRequest and ConnStateData structures
++ * so we can pass this new request off to the routines in
++ * client_side.c.
++ */
++static void
++icapReqModInterpretHttpRequest(IcapStateData * icap, request_t * request)
++{
++ clientHttpRequest *http = icapReqModCreateClientState(icap, request);
++ if (NULL == http)
++ return;
++ /*
++ * bits from clientReadRequest
++ */
++ request->content_length = httpHeaderGetSize(&request->header,
++ HDR_CONTENT_LENGTH);
++ if (!urlCheckRequest(request) ||
++ httpHeaderHas(&request->header, HDR_TRANSFER_ENCODING)) {
++ ErrorState *err;
++ err = errorCon(ERR_UNSUP_REQ, HTTP_NOT_IMPLEMENTED);
++ err->request = requestLink(request);
++ request->flags.proxy_keepalive = 0;
++ http->entry =
++ clientCreateStoreEntry(http, request->method, null_request_flags);
++ errorAppendEntry(http->entry, err);
++ return;
++ }
++ if (!clientCheckContentLength(request)) {
++ ErrorState *err;
++ err = errorCon(ERR_INVALID_REQ, HTTP_LENGTH_REQUIRED);
++ err->request = requestLink(request);
++ http->entry =
++ clientCreateStoreEntry(http, request->method, null_request_flags);
++ errorAppendEntry(http->entry, err);
++ return;
++ }
++ /* Do we expect a request-body? */
++ if (request->content_length > 0) {
++ debug(81, 5) ("handing request bodies in ICAP REQMOD\n");
++ if (request->body_reader_data)
++ cbdataUnlock(request->body_reader_data);
++ request->body_reader = icapReqModBodyReader;
++ request->body_reader_data = icap; /* XXX cbdataLock? */
++ cbdataLock(icap); /*Yes sure ..... */
++ memBufDefInit(&icap->reqmod.http_entity.buf);
++ }
++ if (clientCachable(http))
++ request->flags.cachable = 1;
++ if (clientHierarchical(http))
++ request->flags.hierarchical = 1;
++ clientProcessRequest(http);
++}
++
++/*
++ * icapReqModParseHttpError
++ *
++ * Handle an error when parsing the new HTTP request we read
++ * from the ICAP server.
++ */
++static void
++icapReqModParseHttpError(IcapStateData * icap, const char *reason)
++{
++ debug(81, 1) ("icapReqModParseHttpError: %s\n", reason);
++}
++
++/*
++ * icapEntryError
++ *
++ * A wrapper for errorCon() and errorAppendEntry().
++ */
++static void
++icapEntryError(IcapStateData * icap, err_type et, http_status hs, int xerrno)
++{
++ ErrorState *err;
++ clientHttpRequest *http = icapReqModCreateClientState(icap, NULL);
++ if (NULL == http)
++ return;
++ http->entry = clientCreateStoreEntry(http,
++ icap->request->method, null_request_flags);
++ err = errorCon(et, hs);
++ err->xerrno = xerrno;
++ err->request = requestLink(icap->request);
++ errorAppendEntry(http->entry, err);
++}
++
++/*
++ * icapReqModParseHttpRequest
++ *
++ * Parse the HTTP request that we read from the ICAP server.
++ * Creates and fills in the request_t structure.
++ */
++static void
++icapReqModParseHttpRequest(IcapStateData * icap)
++{
++ char *mstr;
++ char *uri;
++ char *inbuf;
++ char *t;
++ char *token;
++ char *headers;
++ method_t method;
++ request_t *request;
++ http_version_t http_ver;
++ int reqlen = icap->reqmod.hdr_buf.size;
++ int hdrlen;
++
++ /*
++ * Lazy, make a copy of the buf so I can chop it up with strtok()
++ */
++ inbuf = xcalloc(reqlen + 1, 1);
++ memcpy(inbuf, icap->reqmod.hdr_buf.buf, reqlen);
++
++ if ((mstr = strtok(inbuf, "\t ")) == NULL) {
++ debug(81, 1) ("icapReqModParseHttpRequest: Can't get request method\n");
++ icapReqModParseHttpError(icap, "error:invalid-request-method");
++ xfree(inbuf);
++ return;
++ }
++ method = urlParseMethod(mstr);
++ if (method == METHOD_NONE) {
++ debug(81, 1) ("icapReqModParseHttpRequest: Unsupported method '%s'\n",
++ mstr);
++ icapReqModParseHttpError(icap, "error:unsupported-request-method");
++ xfree(inbuf);
++ return;
++ }
++ /* look for URL+HTTP/x.x */
++ if ((uri = strtok(NULL, "\n")) == NULL) {
++ debug(81, 1) ("icapReqModParseHttpRequest: Missing URI\n");
++ icapReqModParseHttpError(icap, "error:missing-url");
++ xfree(inbuf);
++ return;
++ }
++ while (xisspace(*uri))
++ uri++;
++ t = uri + strlen(uri);
++ assert(*t == '\0');
++ token = NULL;
++ while (t > uri) {
++ t--;
++ if (xisspace(*t) && !strncmp(t + 1, "HTTP/", 5)) {
++ token = t + 1;
++ break;
++ }
++ }
++ while (t > uri && xisspace(*t))
++ *(t--) = '\0';
++ debug(81, 5) ("icapReqModParseHttpRequest: URI is '%s'\n", uri);
++ if (token == NULL) {
++ debug(81, 3) ("icapReqModParseHttpRequest: Missing HTTP identifier\n");
++ icapReqModParseHttpError(icap, "error:missing-http-ident");
++ xfree(inbuf);
++ return;
++ }
++ if (sscanf(token + 5, "%d.%d", &http_ver.major, &http_ver.minor) != 2) {
++ debug(81, 3) ("icapReqModParseHttpRequest: Invalid HTTP identifier.\n");
++ icapReqModParseHttpError(icap, "error:invalid-http-ident");
++ xfree(inbuf);
++ return;
++ }
++ debug(81, 6) ("icapReqModParseHttpRequest: Client HTTP version %d.%d.\n",
++ http_ver.major, http_ver.minor);
++
++ headers = strtok(NULL, null_string);
++ hdrlen = inbuf + reqlen - headers;
++
++ if ((request = urlParse(method, uri)) == NULL) {
++ debug(81, 3) ("Invalid URL: %s at %s:%d\n", uri, __FILE__, __LINE__);
++ icapEntryError(icap, ERR_INVALID_URL, HTTP_BAD_REQUEST, 0);
++ xfree(inbuf);
++ return;
++ }
++ /* compile headers */
++ if (!httpHeaderParse(&request->header, headers, headers + hdrlen)) {
++ debug(81, 3) ("Failed to parse HTTP headers for: %s at %s:%d",
++ uri, __FILE__, __LINE__);
++ icapEntryError(icap, ERR_INVALID_REQ, HTTP_BAD_REQUEST, 0);
++ xfree(inbuf);
++ return;
++ }
++ debug(81,
++ 3)
++ ("icapReqModParseHttpRequest: successfully parsed the HTTP request\n");
++ request->http_ver = http_ver;
++ request->client_addr = icap->request->client_addr;
++ request->client_port = icap->request->client_port;
++ request->my_addr = icap->request->my_addr;
++ request->my_port = icap->request->my_port;
++ request->class = icap->request->class;
++ if (icap->request->auth_user_request) {
++ /* Copy authentification info in new request */
++ request->auth_user_request = icap->request->auth_user_request;
++ authenticateAuthUserRequestLock(request->auth_user_request);
++ }
++ request->content_length = httpHeaderGetSize(&request->header,
++ HDR_CONTENT_LENGTH);
++ if (strBuf(icap->request->extacl_log))
++ request->extacl_log = stringDup(&icap->request->extacl_log);
++ if (icap->request->extacl_user)
++ request->extacl_user = xstrdup(icap->request->extacl_user);
++ if (icap->request->extacl_passwd)
++ request->extacl_passwd = xstrdup(icap->request->extacl_passwd);
++#if ICAP_PROXY_KEEP_ALIVE
++ /*
++ * Copy the proxy_keepalive flag from the original request
++ */
++ request->flags.proxy_keepalive = icap->request->flags.proxy_keepalive;
++ /*
++ * If proxy_keepalive was set for the original request, make
++ * sure that the adapated request also has the necessary headers
++ * for keepalive
++ */
++ if (request->flags.proxy_keepalive) {
++ if (!httpMsgIsPersistent(http_ver, &request->header))
++ request->flags.proxy_keepalive = 0;
++ }
++#endif
++ icapReqModInterpretHttpRequest(icap, request);
++ xfree(inbuf);
++}
++
++/*
++ * icapReqModHandoffRespMod
++ *
++ * Handles the case where a REQMOD request results in an HTTP REPLY
++ * (instead of an ICAP REPLY that contains a new HTTP REQUEST). We
++ * prepare the IcapStateData for passing off to the icap_reqmod
++ * code, where we have functions for reading HTTP replies in ICAP
++ * messages.
++ */
++static void
++icapReqModHandoffRespMod(IcapStateData * icap)
++{
++ extern PF icapReadReply;
++ clientHttpRequest *http = icapReqModCreateClientState(icap, NULL);
++ if (NULL == http)
++ return;
++ assert(icap->request);
++
++ http->entry = clientCreateStoreEntry(http,
++ icap->request->method, icap->request->flags);
++ icap->respmod.entry = http->entry;
++ storeLockObject(icap->respmod.entry);
++
++ /* icap->http_flags = ? */
++ memBufDefInit(&icap->respmod.buffer);
++ memBufDefInit(&icap->chunk_buf);
++ assert(icap->current_service);
++ icapReadReply(icap->icap_fd, icap);
++}
++
++/*
++ * icapReqModKeepAliveOrClose
++ *
++ * Called when we are done reading from the ICAP server.
++ * Either close the connection or keep it open for a future
++ * transaction.
++ */
++static void
++icapReqModKeepAliveOrClose(IcapStateData * icap)
++{
++ int fd = icap->icap_fd;
++ debug(81, 3) ("%s:%d FD %d\n", __FILE__, __LINE__, fd);
++ if (fd < 0)
++ return;
++ if (!icap->flags.keep_alive) {
++ debug(81, 3) ("%s:%d keep_alive not set, closing\n", __FILE__,
++ __LINE__);
++ comm_close(fd);
++ return;
++ }
++ if (icap->request->content_length < 0) {
++ /* no message body */
++ debug(81, 3) ("%s:%d no message body\n", __FILE__, __LINE__);
++ if (1 != icap->reqmod.hdr_state) {
++ /* didn't get to end of HTTP headers */
++ debug(81, 3) ("%s:%d didnt find end of headers, closing\n",
++ __FILE__, __LINE__);
++ comm_close(fd);
++ return;
++ }
++ } else if (icap->reqmod.http_entity.bytes_read !=
++ icap->request->content_length) {
++ debug(81, 3) ("%s:%d bytes_read (%" PRINTF_OFF_T ") != content_length (%" PRINTF_OFF_T ")\n",
++ __FILE__, __LINE__, icap->reqmod.http_entity.bytes_read,
++ icap->request->content_length);
++ /* an error */
++ comm_close(fd);
++ return;
++ }
++ debug(81, 3) ("%s:%d looks good, keeping alive\n", __FILE__, __LINE__);
++ commSetDefer(fd, NULL, NULL);
++ commSetTimeout(fd, -1, NULL, NULL);
++ commSetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0);
++ comm_remove_close_handler(fd, icapStateFree, icap);
++ pconnPush(fd, icap->current_service->hostname, icap->current_service->port, NULL, NULL, 0);
++ icap->icap_fd = -1;
++ icapStateFree(-1, icap);
++}
++
++/*
++ * icapReqModReadHttpHdrs
++ *
++ * Read the HTTP reply from the ICAP server. Uses the values
++ * from the ICAP Encapsulation header to know how many bytes
++ * to read.
++ */
++static void
++icapReqModReadHttpHdrs(int fd, void *data)
++{
++ IcapStateData *icap = data;
++ LOCAL_ARRAY(char, tmpbuf, SQUID_TCP_SO_RCVBUF);
++ int rl;
++ debug(81, 3) ("icapReqModReadHttpHdrs:\n");
++ assert(fd == icap->icap_fd);
++ assert(icap->enc.req_hdr == 0);
++ if (0 == icap->reqmod.hdr_state) {
++ int expect = icapExpectedHttpReqHdrSize(icap);
++ int so_far = icap->http_header_bytes_read_so_far;
++ int needed = expect - so_far;
++ debug(81, 3) ("expect=%d\n", expect);
++ debug(81, 3) ("so_far=%d\n", so_far);
++ debug(81, 3) ("needed=%d\n", needed);
++ assert(needed >= 0);
++ if (0 == expect) {
++ fatalf("unexpected condition in %s:%d", __FILE__, __LINE__);
++ }
++ rl = FD_READ_METHOD(fd, tmpbuf, needed);
++ debug(81, 3) ("icapReqModReadHttpHdrs: read %d bytes\n", rl);
++ if (rl < 0) {
++ fatalf("need to handle read error at %s:%d", __FILE__, __LINE__);
++ }
++ fd_bytes(fd, rl, FD_READ);
++ kb_incr(&statCounter.icap.all.kbytes_in, rl);
++ memBufAppend(&icap->reqmod.hdr_buf, tmpbuf, rl);
++ icap->http_header_bytes_read_so_far += rl;
++ if (rl != needed) {
++ /* still more header data to read */
++ commSetSelect(fd, COMM_SELECT_READ, icapReqModReadHttpHdrs, icap,
++ 0);
++ return;
++ }
++ icap->reqmod.hdr_state = 1;
++ }
++ assert(1 == icap->reqmod.hdr_state);
++ debug(81, 3) ("icapReqModReadHttpHdrs: read the entire request headers\n");
++ icapReqModParseHttpRequest(icap);
++ if (-1 == icap->reqmod.client_fd) {
++ /* we detected that the original client_side went away */
++ icapReqModKeepAliveOrClose(icap);
++ } else if (icap->enc.req_body > -1) {
++ icap->chunk_size = 0;
++ memBufDefInit(&icap->chunk_buf);
++ commSetSelect(fd, COMM_SELECT_READ, icapReqModReadHttpBody, icap, 0);
++ } else {
++ icapReqModKeepAliveOrClose(icap);
++ }
++}
++
++
++/*
++ * icapReqModReadIcapPart
++ *
++ * Read the ICAP reply header.
++ */
++static void
++icapReqModReadIcapPart(int fd, void *data)
++{
++ IcapStateData *icap = data;
++ int version_major, version_minor;
++ const char *str_status;
++ int x;
++ const char *start;
++ const char *end;
++ int status;
++ int isIcap = 0;
++ int directResponse = 0;
++
++ debug(81, 5) ("icapReqModReadIcapPart: FD %d httpState = %p\n", fd, data);
++ statCounter.syscalls.sock.reads++;
++
++ x = icapReadHeader(fd, icap, &isIcap);
++ if (x < 0) {
++ /* Did not find a proper ICAP response */
++ debug(81, 3) ("ICAP : Error path!\n");
++ icapEntryError(icap, ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR,
++ errno);
++ comm_close(fd);
++ return;
++ }
++ if (x == 0) {
++ /*
++ * Waiting for more headers. Schedule new read hander, but
++ * don't reset timeout.
++ */
++ commSetSelect(fd, COMM_SELECT_READ, icapReqModReadIcapPart, icap, 0);
++ return;
++ }
++ /*
++ * Parse the ICAP header
++ */
++ assert(icap->icap_hdr.size);
++ debug(81, 3) ("Read icap header : <%s>\n", icap->icap_hdr.buf);
++ if ((status =
++ icapParseStatusLine(icap->icap_hdr.buf, icap->icap_hdr.size,
++ &version_major, &version_minor, &str_status)) < 0) {
++ debug(81, 1) ("BAD ICAP status line <%s>\n", icap->icap_hdr.buf);
++ /* is this correct in case of ICAP protocol error? */
++ icapEntryError(icap, ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR,
++ errno);
++ comm_close(fd);
++ return;
++ };
++ if (200 != status && 201 != status) {
++ debug(81, 1) ("Unsupported status '%d' from ICAP server\n", status);
++ icapEntryError(icap, ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR,
++ errno);
++ comm_close(fd);
++ return;
++ }
++ icapSetKeepAlive(icap, icap->icap_hdr.buf);
++ if (icapFindHeader(icap->icap_hdr.buf, "Encapsulated:", &start, &end)) {
++ icapParseEncapsulated(icap, start, end);
++ } else {
++ debug(81,
++ 1)
++ ("WARNING: icapReqModReadIcapPart() did not find 'Encapsulated' header\n");
++ }
++ if (icap->enc.res_hdr > -1)
++ directResponse = 1;
++ else if (icap->enc.res_body > -1)
++ directResponse = 1;
++ else
++ directResponse = 0;
++ debug(81, 3) ("icapReqModReadIcapPart: directResponse=%d\n",
++ directResponse);
++
++ /* Check whether it is a direct reply - if so over to http part */
++ if (directResponse) {
++ debug(81,
++ 3)
++ ("icapReqModReadIcapPart: FD %d, processing HTTP response for REQMOD!\n",
++ fd);
++ /* got the reply, no need to come here again */
++ icap->flags.wait_for_reply = 0;
++ icap->flags.got_reply = 1;
++ icapReqModHandoffRespMod(icap);
++ return;
++ }
++ memBufDefInit(&icap->reqmod.hdr_buf);
++ commSetSelect(fd, COMM_SELECT_READ, icapReqModReadHttpHdrs, icap, 0);
++ return;
++}
++
++/*
++ * icapSendReqModDone
++ *
++ * Called after we've sent the ICAP request. Checks for errors
++ * and installs the handler functions for the next step.
++ */
++static void
++icapSendReqModDone(int fd, char *bufnotused, size_t size, int errflag,
++ void *data)
++{
++ IcapStateData *icap = data;
++
++ debug(81, 5) ("icapSendReqModDone: FD %d: size %d: errflag %d.\n",
++ fd, size, errflag);
++ if (size > 0) {
++ fd_bytes(fd, size, FD_WRITE);
++ kb_incr(&statCounter.icap.all.kbytes_out, size);
++ }
++ if (errflag == COMM_ERR_CLOSING)
++ return;
++ if (errflag) {
++ debug(81, 3) ("icapSendReqModDone: unreachable=1, service=%s\n",
++ icap->current_service->uri);
++ icapOptSetUnreachable(icap->current_service);
++ icapEntryError(icap, ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR,
++ errno);
++ comm_close(fd);
++ return;
++ }
++ /* Schedule read reply. */
++ commSetSelect(fd, COMM_SELECT_READ, icapReqModReadIcapPart, icap, 0);
++ /*
++ * Set the read timeout here because it hasn't been set yet.
++ * We only set the read timeout after the request has been
++ * fully written to the server-side. If we start the timeout
++ * after connection establishment, then we are likely to hit
++ * the timeout for POST/PUT requests that have very large
++ * request bodies.
++ */
++ commSetTimeout(fd, Config.Timeout.read, icapConnectTimeout, icap);
++}
++
++
++/*
++ * icapSendReqMod
++ *
++ * Send the ICAP request, including HTTP request, to the ICAP server
++ * after connection has been established.
++ */
++static void
++icapSendReqMod(int fd, int status, void *data)
++{
++ MemBuf mb;
++ MemBuf mb_hdr;
++ Packer p;
++ IcapStateData *icap = data;
++ char *client_addr;
++ int icap_fd = icap->icap_fd;
++ icap_service *service;
++ CWCB *theCallback;
++
++ debug(81, 5) ("icapSendReqMod FD %d, status %d\n", fd, status);
++ icap->flags.connect_pending = 0;
++
++ if (COMM_OK != status) {
++ debug(81, 1) ("Could not connect to ICAP server %s:%d: %s\n",
++ icap->current_service->hostname,
++ icap->current_service->port, xstrerror());
++ debug(81, 3) ("icapSendReqMod: unreachable=1, service=%s\n",
++ icap->current_service->uri);
++ icapOptSetUnreachable(icap->current_service);
++ icapEntryError(icap, ERR_ICAP_FAILURE, HTTP_SERVICE_UNAVAILABLE, errno);
++ comm_close(fd);
++ return;
++ }
++ fd_table[fd].pconn.uses++;
++ fd_table[fd].pconn.type = 2;
++ if (icap->request->content_length > 0)
++ theCallback = icapReqModSendBodyChunk;
++ else
++ theCallback = icapSendReqModDone;
++
++ memBufDefInit(&mb);
++ memBufDefInit(&mb_hdr);
++ memBufPrintf(&mb_hdr, "%s %s HTTP/%d.%d\r\n",
++ RequestMethodStr[icap->request->method],
++ icap->reqmod.uri,
++ icap->request->http_ver.major, icap->request->http_ver.minor);
++ packerToMemInit(&p, &mb_hdr);
++ httpHeaderPackInto(&icap->request->header, &p);
++ packerClean(&p);
++ memBufAppend(&mb_hdr, crlf, 2);
++ service = icap->current_service;
++ assert(service);
++ client_addr = inet_ntoa(icap->request->client_addr);
++
++ memBufPrintf(&mb, "REQMOD %s ICAP/1.0\r\n", service->uri);
++ memBufPrintf(&mb, "Encapsulated: req-hdr=0");
++ /* TODO: Change the offset using 'request' if needed */
++ if (icap->request->content_length > 0)
++ memBufPrintf(&mb, ", req-body=%d", mb_hdr.size);
++ else
++ memBufPrintf(&mb, ", null-body=%d", mb_hdr.size);
++ memBufAppend(&mb, crlf, 2);
++
++ if (service->flags.need_x_client_ip && Config.icapcfg.send_client_ip)
++ memBufPrintf(&mb, "X-Client-IP: %s\r\n", client_addr);
++
++ if (service->flags.need_x_server_ip && Config.icapcfg.send_server_ip)
++ icapAddOriginIP(&mb, icap->request->host);
++
++ if ((service->flags.need_x_authenticated_user
++ && Config.icapcfg.send_auth_user)
++ && (icap->request->auth_user_request != NULL))
++ icapAddAuthUserHeader(&mb, icap->request->auth_user_request);
++ if (service->keep_alive) {
++ icap->flags.keep_alive = 1;
++ } else {
++ icap->flags.keep_alive = 0;
++ memBufAppend(&mb, "Connection: close\r\n", 19);
++ }
++ memBufAppend(&mb, crlf, 2);
++ memBufAppend(&mb, mb_hdr.buf, mb_hdr.size);
++ memBufClean(&mb_hdr);
++
++ debug(81, 5) ("icapSendReqMod: FD %d writing {%s}\n", icap->icap_fd,
++ mb.buf);
++ comm_write_mbuf(icap_fd, mb, theCallback, icap);
++}
++
++/*
++ * icapReqModStart
++ *
++ * Initiate an ICAP REQMOD transaction. Create and fill in IcapStateData
++ * structure and request a TCP connection to the server.
++ */
++IcapStateData *
++icapReqModStart(icap_service * service, const char *uri, request_t * request,
++ int fd, struct timeval start, struct in_addr log_addr, void *cookie)
++{
++ IcapStateData *icap = NULL;
++
++ debug(81, 3) ("icapReqModStart: type=%d\n", (int) service->type);
++
++ switch (service->type) {
++ case ICAP_SERVICE_REQMOD_PRECACHE:
++ break;
++ default:
++ fatalf("icapReqModStart: unsupported service type '%s'\n",
++ icap_service_type_str[service->type]);
++ break;
++ }
++
++ if (service->unreachable) {
++ if (service->bypass) {
++ debug(81,
++ 5) ("icapReqModStart: BYPASS because service unreachable: %s\n",
++ service->uri);
++ return NULL;
++ } else {
++ debug(81,
++ 5) ("icapReqModStart: ERROR because service unreachable: %s\n",
++ service->uri);
++ return (IcapStateData *) - 1;
++ }
++ }
++ icap = icapAllocate();
++ if (!icap) {
++ debug(81, 3) ("icapReqModStart: icapAllocate() failed\n");
++ return NULL;
++ }
++ icap->current_service = service;
++ icap->preview_size = service->preview;
++ icap->reqmod.uri = uri; /* XXX should be xstrdup? */
++ icap->reqmod.start = start;
++ icap->reqmod.log_addr = log_addr;
++ icap->request = requestLink(request);
++ icap->reqmod.hdr_state = 0;
++ icap->reqmod.client_fd = fd;
++ icap->reqmod.client_cookie = cookie;
++ cbdataLock(icap->reqmod.client_cookie);
++
++ if (!icapConnect(icap, icapSendReqMod))
++ return NULL;
++
++ statCounter.icap.all.requests++;
++ debug(81, 3) ("icapReqModStart: returning %p\n", icap);
++ return icap;
++}
++
++/*
++ * icapReqModSendBodyChunk
++ *
++ * A "comm_write" callback. This is called after comm_write() does
++ * its job to let us know how things went. If there are no errors,
++ * get another chunk of the body from client_side.
++ */
++static void
++icapReqModSendBodyChunk(int fd, char *bufnotused, size_t size, int errflag,
++ void *data)
++{
++ IcapStateData *icap = data;
++ debug(81, 3) ("icapReqModSendBodyChunk: FD %d wrote %d errflag %d.\n",
++ fd, (int) size, errflag);
++ if (errflag == COMM_ERR_CLOSING)
++ return;
++ if (errflag) {
++ icapEntryError(icap, ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR,
++ errno);
++ comm_close(fd);
++ return;
++ }
++ clientReadBody(icap->request,
++ memAllocate(MEM_8K_BUF), 8192, icapReqModBodyHandler, icap);
++}
++
++/*
++ * icapReqModBodyHandler
++ *
++ * Called after Squid gets a chunk of the request entity from the
++ * client side. The body is chunkified and passed to comm_write.
++ * The comm_write callback depends on whether or not this is the
++ * last chunk.
++ */
++static void
++icapReqModBodyHandler(char *buf, ssize_t size, void *data)
++{
++ IcapStateData *icap = data;
++ MemBuf mb;
++ CWCB *theCallback = icapReqModSendBodyChunk;
++ if (size < 0) {
++ debug(81, 1) ("icapReqModBodyHandler: %s\n", xstrerror());
++ memFree8K(buf);
++ return;
++ }
++ memBufDefInit(&mb);
++ debug(81, 3) ("icapReqModBodyHandler: writing chunk size %d\n", size);
++ memBufPrintf(&mb, "%x\r\n", size);
++ if (size)
++ memBufAppend(&mb, buf, size);
++ else
++ theCallback = icapSendReqModDone;
++ memBufAppend(&mb, crlf, 2);
++ memFree8K(buf);
++ comm_write_mbuf(icap->icap_fd, mb, theCallback, icap);
++}
++
++/*
++ * icapReqModReadHttpBody
++ *
++ * The read handler for the client's HTTP connection when reading
++ * message bodies. Called by comm_select().
++ */
++static void
++icapReqModReadHttpBody(int fd, void *data)
++{
++ IcapStateData *icap = data;
++ int len;
++ debug(81, 3) ("icapReqModReadHttpBody: FD %d called\n", fd);
++ len = memBufRead(fd, &icap->chunk_buf);
++ debug(81, 3) ("icapReqModReadHttpBody: read returns %d\n", len);
++ if (len < 0) {
++ debug(81, 3) ("icapReqModReadHttpBody: FD %d %s\n", fd, xstrerror());
++ if (!ignoreErrno(errno))
++ icap->flags.reqmod_http_entity_eof = 1;
++ } else if (0 == len) {
++ debug(81, 3) ("icapReqModReadHttpBody: FD %d EOF\n", fd);
++ icap->flags.reqmod_http_entity_eof = 1;
++ } else {
++ fd_bytes(fd, len, FD_READ);
++ kb_incr(&statCounter.icap.all.kbytes_in, len);
++ icap->reqmod.http_entity.bytes_read +=
++ icapParseChunkedBody(icap,
++ icapReqModMemBufAppend, &icap->reqmod.http_entity.buf);
++ }
++ if (icap->reqmod.http_entity.bytes_read >= icap->request->content_length)
++ icap->flags.reqmod_http_entity_eof = 1;
++
++ if (!icap->flags.reqmod_http_entity_eof)
++ commSetSelect(fd, COMM_SELECT_READ, icapReqModReadHttpBody, icap, 0);
++ /*
++ * Notify the other side if it is waiting for data from us
++ */
++ debug(81, 3) ("%s:%d http_entity.callback=%p\n", __FILE__, __LINE__,
++ icap->reqmod.http_entity.callback);
++ debug(81, 3) ("%s:%d http_entity.buf.size=%d\n", __FILE__, __LINE__,
++ icap->reqmod.http_entity.buf.size);
++ if (icap->reqmod.http_entity.callback && icap->reqmod.http_entity.buf.size) {
++ icapReqModPassHttpBody(icap,
++ icap->reqmod.http_entity.callback_buf,
++ icap->reqmod.http_entity.callback_bufsize,
++ icap->reqmod.http_entity.callback,
++ icap->reqmod.http_entity.callback_data);
++ icap->reqmod.http_entity.callback = NULL;
++ cbdataUnlock(icap->reqmod.http_entity.callback_data);
++
++ }
++}
++
++/*
++ * icapReqModPassHttpBody
++ *
++ * Called from http.c after request headers have been sent.
++ * This function feeds the http.c module chunks of the request
++ * body that were stored in the http_entity.buf MemBuf.
++ */
++static void
++icapReqModPassHttpBody(IcapStateData * icap, char *buf, size_t size,
++ CBCB * callback, void *cbdata)
++{
++ debug(81, 3) ("icapReqModPassHttpBody: called\n");
++ if (!buf) {
++ debug(81, 1) ("icapReqModPassHttpBody: FD %d called with %p, %d, %p (request aborted)\n",
++ icap->icap_fd, buf, (int) size, cbdata);
++ comm_close(icap->icap_fd);
++ return;
++ }
++ if (!cbdataValid(cbdata)) {
++ debug(81,
++ 1)
++ ("icapReqModPassHttpBody: FD %d callback data invalid, closing\n",
++ icap->icap_fd);
++ comm_close(icap->icap_fd); /*It is better to be sure that the connection will be closed..... */
++ /*icapReqModKeepAliveOrClose(icap); */
++ return;
++ }
++ debug(81, 3) ("icapReqModPassHttpBody: entity buf size = %d\n",
++ icap->reqmod.http_entity.buf.size);
++ if (icap->reqmod.http_entity.buf.size) {
++ int copy_sz = icap->reqmod.http_entity.buf.size;
++ if (copy_sz > size)
++ copy_sz = size;
++ xmemcpy(buf, icap->reqmod.http_entity.buf.buf, copy_sz);
++ /* XXX don't let Alex see this ugliness */
++ xmemmove(icap->reqmod.http_entity.buf.buf,
++ icap->reqmod.http_entity.buf.buf + copy_sz,
++ icap->reqmod.http_entity.buf.size - copy_sz);
++ icap->reqmod.http_entity.buf.size -= copy_sz;
++ debug(81, 3) ("icapReqModPassHttpBody: giving %d bytes to other side\n",
++ copy_sz);
++ callback(buf, copy_sz, cbdata);
++ debug(81, 3) ("icapReqModPassHttpBody: entity buf size now = %d\n",
++ icap->reqmod.http_entity.buf.size);
++ return;
++ }
++ if (icap->flags.reqmod_http_entity_eof) {
++ debug(81, 3) ("icapReqModPassHttpBody: signalling EOF\n");
++ callback(buf, 0, cbdata);
++ icapReqModKeepAliveOrClose(icap);
++ return;
++ }
++ /*
++ * We have no data for the other side at this point. Save all
++ * these values and use them when we do have data.
++ */
++ assert(NULL == icap->reqmod.http_entity.callback);
++ icap->reqmod.http_entity.callback = callback;
++ icap->reqmod.http_entity.callback_data = cbdata;
++ icap->reqmod.http_entity.callback_buf = buf;
++ icap->reqmod.http_entity.callback_bufsize = size;
++ cbdataLock(icap->reqmod.http_entity.callback_data);
++}
++
++/*
++ * Body reader handler for use with request->body_reader function
++ * Simple a wrapper for icapReqModPassHttpBody function
++ */
++
++static void
++icapReqModBodyReader(request_t * request, char *buf, size_t size,
++ CBCB * callback, void *cbdata)
++{
++ IcapStateData *icap = request->body_reader_data;
++ icapReqModPassHttpBody(icap, buf, size, callback, cbdata);
++}
++
++/*
++ * icapReqModMemBufAppend
++ *
++ * stupid wrapper to eliminate compiler warnings
++ */
++static void
++icapReqModMemBufAppend(void *data, const char *buf, ssize_t size)
++{
++ memBufAppend(data, buf, size);
++}
+Index: src/icap_respmod.c
+===================================================================
+RCS file: src/icap_respmod.c
+diff -N src/icap_respmod.c
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ src/icap_respmod.c 25 Jun 2006 10:43:07 -0000 1.1.14.6
+@@ -0,0 +1,1065 @@
++
++/*
++ * $Id$
++ *
++ * DEBUG: section 81 Internet Content Adaptation Protocol (ICAP) Client
++ * AUTHOR: Geetha Manjunath, Hewlett Packard Company
++ *
++ * 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"
++
++static CWCB icapSendRespModDone;
++static PF icapRespModGobble;
++extern PF icapReadReply;
++static PF icapRespModReadReply;
++static void icapRespModKeepAliveOrClose(IcapStateData * icap);
++static int icapReadReply2(IcapStateData * icap);
++static void icapReadReply3(IcapStateData * icap);
++
++#define EXPECTED_ICAP_HEADER_LEN 256
++const char *crlf = "\r\n";
++
++static void
++getICAPRespModString(MemBuf * mb, int o1, int o2, int o3,
++ const char *client_addr, IcapStateData * icap, const icap_service * service)
++{
++ memBufPrintf(mb, "RESPMOD %s ICAP/1.0\r\nEncapsulated:", service->uri);
++ if (o1 >= 0)
++ memBufPrintf(mb, " req-hdr=%1d", o1);
++ if (o2 >= 0)
++ memBufPrintf(mb, ", res-hdr=%1d", o2);
++ if (o3 >= 0)
++ memBufPrintf(mb, ", res-body=%1d", o3);
++ else
++ memBufPrintf(mb, ", null-body=%1d", -o3);
++ memBufPrintf(mb, crlf);
++
++ if (service->flags.need_x_client_ip && Config.icapcfg.send_client_ip) {
++ memBufPrintf(mb, "X-Client-IP: %s\r\n", client_addr);
++ }
++ if (service->flags.need_x_server_ip && Config.icapcfg.send_server_ip)
++ icapAddOriginIP(mb, icap->request->host);
++
++ if ((service->flags.need_x_authenticated_user
++ && Config.icapcfg.send_auth_user)
++ && (icap->request->auth_user_request != NULL)) {
++ icapAddAuthUserHeader(mb, icap->request->auth_user_request);
++ }
++#if NOT_YET_FINISHED
++ if (Config.icapcfg.trailers) {
++ memBufPrintf(mb, "X-TE: trailers\r\n");
++ }
++#endif
++}
++
++static int
++buildRespModHeader(MemBuf * mb, IcapStateData * icap, char *buf,
++ ssize_t len, int theEnd)
++{
++ MemBuf mb_hdr;
++ char *client_addr;
++ int o2 = 0;
++ int o3 = 0;
++ int hlen;
++ int consumed;
++ icap_service *service;
++ HttpReply *r;
++
++ if (memBufIsNull(&icap->respmod.req_hdr_copy))
++ memBufDefInit(&icap->respmod.req_hdr_copy);
++
++ memBufAppend(&icap->respmod.req_hdr_copy, buf, len);
++
++ if (icap->respmod.req_hdr_copy.size > 4 && strncmp(icap->respmod.req_hdr_copy.buf, "HTTP/", 5)) {
++ debug(81, 3) ("buildRespModHeader: Non-HTTP-compliant header: '%s'\n", buf);
++ /*
++ *Possible we can consider that we did not have http responce headers
++ *(maybe HTTP 0.9 protocol), lets returning -1...
++ */
++ consumed = -1;
++ o2 = -1;
++ memBufDefInit(&mb_hdr);
++ httpBuildRequestPrefix(icap->request, icap->request,
++ icap->respmod.entry, &mb_hdr, icap->http_flags);
++ o3 = mb_hdr.size;
++ } else {
++
++ hlen = headersEnd(icap->respmod.req_hdr_copy.buf,
++ icap->respmod.req_hdr_copy.size);
++ debug(81, 3) ("buildRespModHeader: headersEnd = %d(%s)\n", hlen, buf);
++ if (0 == hlen)
++ return 0;
++
++ /*
++ * calc how many bytes from this 'buf' went towards the
++ * reply header.
++ */
++ consumed = hlen - (icap->respmod.req_hdr_copy.size - len);
++ debug(81, 3) ("buildRespModHeader: consumed = %d\n", consumed);
++
++
++ /*
++ * now, truncate our req_hdr_copy at the header end.
++ * this 'if' statement might be unncessary?
++ */
++ if (hlen < icap->respmod.req_hdr_copy.size)
++ icap->respmod.req_hdr_copy.size = hlen;
++
++ /* Copy request header */
++ memBufDefInit(&mb_hdr);
++ httpBuildRequestPrefix(icap->request, icap->request,
++ icap->respmod.entry, &mb_hdr, icap->http_flags);
++ o2 = mb_hdr.size;
++
++ /* Copy response header - Append to request header mbuffer */
++ memBufAppend(&mb_hdr,
++ icap->respmod.req_hdr_copy.buf, icap->respmod.req_hdr_copy.size);
++ o3 = mb_hdr.size;
++ }
++
++ service = icap->current_service;
++ assert(service);
++ client_addr = inet_ntoa(icap->request->client_addr);
++
++ r = httpReplyCreate();
++ httpReplyParse(r, icap->respmod.req_hdr_copy.buf,
++ icap->respmod.req_hdr_copy.size);
++ icap->respmod.res_body_sz = httpReplyBodySize(icap->request->method, r);
++ httpReplyDestroy(r);
++ if (icap->respmod.res_body_sz)
++ getICAPRespModString(mb, 0, o2, o3, client_addr, icap, service);
++ else
++ getICAPRespModString(mb, 0, o2, -o3, client_addr, icap, service);
++ if (Config.icapcfg.preview_enable)
++ if (icap->preview_size >= 0) {
++ memBufPrintf(mb, "Preview: %d\r\n", icap->preview_size);
++ icap->flags.preview_done = 0;
++ }
++ if (service->keep_alive) {
++ icap->flags.keep_alive = 1;
++ memBufAppend(mb, "Connection: keep-alive\r\n", 24);
++ } else {
++ icap->flags.keep_alive = 0;
++ memBufAppend(mb, "Connection: close\r\n", 19);
++ }
++ memBufAppend(mb, crlf, 2);
++ memBufAppend(mb, mb_hdr.buf, mb_hdr.size);
++ memBufClean(&mb_hdr);
++
++
++ return consumed;
++}
++
++
++void
++icapSendRespMod(IcapStateData * icap, char *buf, int len, int theEnd)
++{
++ MemBuf mb;
++#if ICAP_PREVIEW
++ int size;
++ const int preview_size = icap->preview_size;
++#endif
++ debug(81, 5) ("icapSendRespMod: FD %d, len %d, theEnd %d\n",
++ icap->icap_fd, len, theEnd);
++
++ if (icap->flags.no_content) {
++ /*
++ * ICAP server said there are no modifications to make, so
++ * just append this data to the StoreEntry
++ */
++ if (icap->respmod.resp_copy.size) {
++ /*
++ * first copy the data that we already sent to the ICAP server
++ */
++ memBufAppend(&icap->chunk_buf,
++ icap->respmod.resp_copy.buf, icap->respmod.resp_copy.size);
++ icap->respmod.resp_copy.size = 0;
++ }
++ debug(81, 5) ("icapSendRepMod: len=%d theEnd=%d write_pending=%d\n",
++ len, theEnd, icap->flags.write_pending);
++ if (len) {
++ /*
++ * also copy any new data from the HTTP side
++ */
++ memBufAppend(&icap->chunk_buf, buf, len);
++ }
++ (void) icapReadReply2(icap);
++ return;
++ }
++ if (theEnd) {
++ if (icap->respmod.res_body_sz)
++ icap->flags.send_zero_chunk = 1;
++ icap->flags.http_server_eof = 1;
++ }
++ /*
++ * httpReadReply is going to call us with a chunk and then
++ * right away again with an EOF if httpPconnTransferDone() is true.
++ * Since the first write is already dispatched, we'll have to
++ * hack this in somehow.
++ */
++ if (icap->flags.write_pending) {
++ debug(81, 3) ("icapSendRespMod: oops, write_pending=1\n");
++ assert(theEnd);
++ assert(len == 0);
++ return;
++ }
++ if (!cbdataValid(icap)) {
++ debug(81, 3) ("icapSendRespMod: failed to establish connection?\n");
++ return;
++ }
++ memBufDefInit(&mb);
++
++#if SUPPORT_ICAP_204 || ICAP_PREVIEW
++ /*
++ * make a copy of the response in case ICAP server gives us a 204
++ */
++ /*
++ * This piece of code is problematic for 204 responces outside preview.
++ * The icap->respmod.resp_copy continues to filled until we had responce
++ * If the icap server waits to gets all data before sends its responce
++ * then we are puting all downloading object to the main system memory.
++ * My opinion is that 204 responces outside preview must be disabled .....
++ * /chtsanti
++ */
++
++ if (len && icap->flags.copy_response) {
++ if (memBufIsNull(&icap->respmod.resp_copy))
++ memBufDefInit(&icap->respmod.resp_copy);
++ memBufAppend(&icap->respmod.resp_copy, buf, len);
++ }
++#endif
++
++ if (icap->sc == 0) {
++ // http connection has been closed without sending us anything
++ if (len == 0 && theEnd == 1) {
++ ErrorState *err;
++ err = errorCon(ERR_INVALID_RESP, HTTP_BAD_GATEWAY);
++ err->request = requestLink(icap->request);
++ errorAppendEntry(icap->respmod.entry, err);
++ comm_close(icap->icap_fd);
++ return;
++ }
++ /* No data sent yet. Start with headers */
++ if ((icap->sc = buildRespModHeader(&mb, icap, buf, len, theEnd)) > 0) {
++ buf += icap->sc;
++ len -= icap->sc;
++ }
++ /*
++ * Then we do not have http responce headers. All data (previous and those in buf)
++ * now are exist to icap->respmod.req_hdr_copy. Lets get them back.......
++ */
++ if (icap->sc < 0) {
++ memBufAppend(&icap->respmod.buffer,
++ icap->respmod.req_hdr_copy.buf,
++ icap->respmod.req_hdr_copy.size);
++ icap->sc = icap->respmod.req_hdr_copy.size;
++ icap->respmod.req_hdr_copy.size = 0;
++ buf = NULL;
++ len = 0;
++ }
++ }
++ if (0 == icap->sc) {
++ /* check again; bail if we're not ready to send ICAP/HTTP hdrs */
++ debug(81, 5) ("icapSendRespMod: dont have full HTTP response hdrs\n");
++ memBufClean(&mb);
++ return;
++ }
++#if ICAP_PREVIEW
++ if (preview_size < 0 || !Config.icapcfg.preview_enable) /* preview feature off */
++ icap->flags.preview_done = 1;
++
++ if (!icap->flags.preview_done) {
++ /* preview not yet sent */
++ if (icap->sc > 0 && icap->respmod.buffer.size <= preview_size
++ && len > 0) {
++ /* Try to collect at least preview_size+1 bytes */
++ /* By collecting one more byte than needed for preview we know best */
++ /* whether we have to send the ieof chunk extension */
++ size = icap->respmod.buffer.size + len;
++ if (size > preview_size + 1)
++ size = preview_size + 1;
++ size -= icap->respmod.buffer.size;
++ debug(81,
++ 3)
++ ("icapSendRespMod: FD %d: copy %d more bytes to preview buffer.\n",
++ icap->icap_fd, size);
++ memBufAppend(&icap->respmod.buffer, buf, size);
++ buf = ((char *) buf) + size;
++ len -= size;
++ }
++ if (icap->respmod.buffer.size > preview_size || theEnd) {
++ /* we got enough bytes for preview or this is the last call */
++ /* add preview preview now */
++ if (icap->respmod.buffer.size > 0) {
++ size = icap->respmod.buffer.size;
++ if (size > preview_size)
++ size = preview_size;
++ memBufPrintf(&mb, "%x\r\n", size);
++ memBufAppend(&mb, icap->respmod.buffer.buf, size);
++ memBufAppend(&mb, crlf, 2);
++ icap->sc += size;
++ }
++ if (icap->respmod.buffer.size <= preview_size) {
++ /* content length is less than preview size+1 */
++ if (icap->respmod.res_body_sz)
++ memBufAppend(&mb, "0; ieof\r\n\r\n", 11);
++ memBufReset(&icap->respmod.buffer); /* will now be used for other data */
++ } else {
++ char ch;
++ memBufAppend(&mb, "0\r\n\r\n", 5);
++ /* end of preview, wait for continue or 204 signal */
++ /* copy the extra byte and all other data to the icap buffer */
++ /* so that it can be handled next time */
++ ch = icap->respmod.buffer.buf[preview_size];
++ memBufReset(&icap->respmod.buffer); /* will now be used for other data */
++ memBufAppend(&icap->respmod.buffer, &ch, 1);
++ debug(81,
++ 3)
++ ("icapSendRespMod: FD %d: sending preview and keeping %d bytes in internal buf.\n",
++ icap->icap_fd, len + 1);
++ if (len > 0)
++ memBufAppend(&icap->respmod.buffer, buf, len);
++ }
++ icap->flags.preview_done = 1;
++ icap->flags.wait_for_preview_reply = 1;
++ }
++ } else if (icap->flags.wait_for_preview_reply) {
++ /* received new data while waiting for preview response */
++ /* add data to internal buffer and send later */
++ debug(81,
++ 3)
++ ("icapSendRespMod: FD %d: add %d more bytes to internal buf while waiting for preview-response.\n",
++ icap->icap_fd, len);
++ if (len > 0)
++ memBufAppend(&icap->respmod.buffer, buf, len);
++ /* do not send any data now while waiting for preview response */
++ /* but prepare for read more data on the HTTP connection */
++ memBufClean(&mb);
++ return;
++ } else
++#endif
++ {
++ /* after preview completed and ICAP preview response received */
++ /* there may still be some data in the buffer */
++ if (icap->respmod.buffer.size > 0) {
++ memBufPrintf(&mb, "%x\r\n", icap->respmod.buffer.size);
++ memBufAppend(&mb, icap->respmod.buffer.buf,
++ icap->respmod.buffer.size);
++ memBufAppend(&mb, crlf, 2);
++ icap->sc += icap->respmod.buffer.size;
++ memBufReset(&icap->respmod.buffer);
++ }
++ if (len > 0) {
++ memBufPrintf(&mb, "%x\r\n", len);
++ memBufAppend(&mb, buf, len);
++ memBufAppend(&mb, crlf, 2);
++ icap->sc += len;
++ }
++ if (icap->flags.send_zero_chunk) {
++ /* send zero end chunk */
++ icap->flags.send_zero_chunk = 0;
++ icap->flags.http_server_eof = 1;
++ memBufAppend(&mb, "0\r\n\r\n", 5);
++ }
++ /* wait for data coming from ICAP server as soon as we sent something */
++ /* but of course only until we got the response header */
++ if (!icap->flags.got_reply)
++ icap->flags.wait_for_reply = 1;
++ }
++ commSetTimeout(icap->icap_fd, -1, NULL, NULL);
++
++ if (!mb.size) {
++ memBufClean(&mb);
++ return;
++ }
++ debug(81, 5) ("icapSendRespMod: FD %d writing {%s}\n", icap->icap_fd,
++ mb.buf);
++ icap->flags.write_pending = 1;
++ comm_write_mbuf(icap->icap_fd, mb, icapSendRespModDone, icap);
++}
++
++static void
++icapRespModReadReply(int fd, void *data)
++{
++ IcapStateData *icap = data;
++ int version_major, version_minor;
++ const char *str_status;
++ int x;
++ int status = 0;
++ int isIcap = 0;
++ int directResponse = 0;
++ ErrorState *err;
++ const char *start;
++ const char *end;
++
++ debug(81, 5) ("icapRespModReadReply: FD %d data = %p\n", fd, data);
++ statCounter.syscalls.sock.reads++;
++
++ x = icapReadHeader(fd, icap, &isIcap);
++ if (x < 0) {
++ /* Did not find a proper ICAP response */
++ debug(81, 3) ("ICAP : Error path!\n");
++ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
++ err->request = requestLink(icap->request);
++ err->xerrno = errno;
++ errorAppendEntry(icap->respmod.entry, err);
++ comm_close(fd);
++ return;
++ }
++ if (x == 0) {
++ /*
++ * Waiting for more headers. Schedule new read hander, but
++ * don't reset timeout.
++ */
++ commSetSelect(fd, COMM_SELECT_READ, icapRespModReadReply, icap, 0);
++ return;
++ }
++ /*
++ * Parse the ICAP header
++ */
++ assert(icap->icap_hdr.size);
++ debug(81, 3) ("Parse icap header : <%s>\n", icap->icap_hdr.buf);
++ if ((status =
++ icapParseStatusLine(icap->icap_hdr.buf, icap->icap_hdr.size,
++ &version_major, &version_minor, &str_status)) < 0) {
++ debug(81, 1) ("BAD ICAP status line <%s>\n", icap->icap_hdr.buf);
++ /* is this correct in case of ICAP protocol error? */
++ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
++ err->request = requestLink(icap->request);
++ err->xerrno = errno;
++ errorAppendEntry(icap->respmod.entry, err);
++ comm_close(fd);
++ return;
++ };
++ /* OK here we have responce. Lets stop filling the
++ * icap->respmod.resp_copy buffer ....
++ */
++ icap->flags.copy_response = 0;
++
++ icapSetKeepAlive(icap, icap->icap_hdr.buf);
++#if ICAP_PREVIEW
++ if (icap->flags.wait_for_preview_reply) {
++ if (100 == status) {
++ debug(81, 5) ("icapRespModReadReply: 100 Continue received\n");
++ icap->flags.wait_for_preview_reply = 0;
++ /* if http_server_eof
++ * call again icapSendRespMod to handle data that
++ * was received while waiting for this ICAP response
++ * else let http to call icapSendRespMod when new data arrived
++ */
++ if (icap->flags.http_server_eof)
++ icapSendRespMod(icap, NULL, 0, 0);
++ /*
++ * reset the header to send the rest of the preview
++ */
++ if (!memBufIsNull(&icap->icap_hdr))
++ memBufReset(&icap->icap_hdr);
++
++ /*We do n't need it any more ....... */
++ if (!memBufIsNull(&icap->respmod.resp_copy))
++ memBufClean(&icap->respmod.resp_copy);
++
++ return;
++ }
++ if (204 == status) {
++ debug(81,
++ 5) ("icapRespModReadReply: 204 No modification received\n");
++ icap->flags.wait_for_preview_reply = 0;
++ }
++ }
++#endif /*ICAP_PREVIEW */
++
++#if SUPPORT_ICAP_204 || ICAP_PREVIEW
++ if (204 == status) {
++ debug(81, 3) ("got 204 status from ICAP server\n");
++ icapRespModKeepAliveOrClose(icap);
++
++ debug(81, 3) ("setting icap->flags.no_content\n");
++ icap->flags.no_content = 1;
++ /*
++ * copy the response already written to the ICAP server
++ */
++ debug(81, 3) ("copying %d bytes from resp_copy to chunk_buf\n",
++ icap->respmod.resp_copy.size);
++ memBufAppend(&icap->chunk_buf,
++ icap->respmod.resp_copy.buf, icap->respmod.resp_copy.size);
++ icap->respmod.resp_copy.size = 0;
++ if (icapReadReply2(icap) < 0)
++ icapStateFree(-1, icap);
++
++ /*
++ * XXX ideally want to clean icap->respmod.resp_copy here
++ * XXX ideally want to "close" ICAP server connection here
++ * OK do it....
++ */
++ if (!memBufIsNull(&icap->respmod.resp_copy))
++ memBufClean(&icap->respmod.resp_copy);
++ return;
++ }
++#endif
++ if (200 != status && 201 != status) {
++ debug(81, 1) ("Unsupported status '%d' from ICAP server\n", status);
++ /* Did not find a proper ICAP response */
++ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
++ err->request = requestLink(icap->request);
++ err->xerrno = errno;
++ errorAppendEntry(icap->respmod.entry, err);
++ comm_close(fd);
++ return;
++ }
++ if (icapFindHeader(icap->icap_hdr.buf, "Encapsulated:", &start, &end)) {
++ icapParseEncapsulated(icap, start, end);
++ } else {
++ debug(81,
++ 1)
++ ("WARNING: icapRespModReadReply() did not find 'Encapsulated' header\n");
++ }
++ if (icap->enc.res_hdr > -1)
++ directResponse = 1;
++ else if (icap->enc.res_body > -1)
++ directResponse = 1;
++ else
++ directResponse = 0;
++
++ /*
++ * "directResponse" is the normal case here. If we don't have
++ * a response header or body, it is an error.
++ */
++ if (!directResponse) {
++ /* Did not find a proper ICAP response */
++ debug(81, 3) ("ICAP : Error path!\n");
++ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
++ err->request = requestLink(icap->request);
++ err->xerrno = errno;
++ errorAppendEntry(icap->respmod.entry, err);
++ comm_close(fd);
++ return;
++ }
++ /* got the reply, no need to come here again */
++ icap->flags.wait_for_reply = 0;
++ icap->flags.got_reply = 1;
++ /* Next, gobble any data before the HTTP response starts */
++ if (icap->enc.res_hdr > -1)
++ icap->bytes_to_gobble = icap->enc.res_hdr;
++ commSetSelect(fd, COMM_SELECT_READ, icapRespModGobble, icap, 0);
++}
++
++
++/*
++ * Gobble up (read) some bytes until we get to the start of the body
++ */
++static void
++icapRespModGobble(int fd, void *data)
++{
++ IcapStateData *icap = data;
++ int len;
++ LOCAL_ARRAY(char, junk, SQUID_TCP_SO_RCVBUF);
++ debug(81, 3) ("icapRespModGobble: FD %d gobbling %d bytes\n", fd,
++ icap->bytes_to_gobble);
++ len = FD_READ_METHOD(fd, junk, icap->bytes_to_gobble);
++ debug(81, 3) ("icapRespModGobble: gobbled %d bytes\n", len);
++ if (len < 0) {
++ /* XXX error */
++ abort();
++ }
++ icap->bytes_to_gobble -= len;
++ if (icap->bytes_to_gobble)
++ commSetSelect(fd, COMM_SELECT_READ, icapRespModGobble, icap, 0);
++ else
++ icapReadReply(fd, icap);
++}
++
++
++static void
++icapSendRespModDone(int fd, char *bufnotused, size_t size, int errflag,
++ void *data)
++{
++ IcapStateData *icap = data;
++ ErrorState *err;
++
++ icap->flags.write_pending = 0;
++ debug(81, 5) ("icapSendRespModDone: FD %d: size %d: errflag %d.\n",
++ fd, size, errflag);
++ if (size > 0) {
++ fd_bytes(fd, size, FD_WRITE);
++ kb_incr(&statCounter.icap.all.kbytes_out, size);
++ }
++ if (errflag == COMM_ERR_CLOSING)
++ return;
++ if (errflag) {
++ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
++ err->xerrno = errno;
++ if (cbdataValid(icap))
++ err->request = requestLink(icap->request);
++ storeEntryReset(icap->respmod.entry);
++ errorAppendEntry(icap->respmod.entry, err);
++ comm_close(fd);
++ return;
++ }
++ if (EBIT_TEST(icap->respmod.entry->flags, ENTRY_ABORTED)) {
++ debug(81, 3) ("icapSendRespModDone: Entry Aborded\n");
++ comm_close(fd);
++ return;
++ }
++ if (icap->flags.send_zero_chunk) {
++ debug(81,
++ 3) ("icapSendRespModDone: I'm supposed to send zero chunk now\n");
++ icap->flags.send_zero_chunk = 0;
++ icapSendRespMod(icap, NULL, 0, 1);
++ return;
++ }
++ if (icap->flags.wait_for_preview_reply || icap->flags.wait_for_reply) {
++ /* Schedule reading the ICAP response */
++ debug(81,
++ 3)
++ ("icapSendRespModDone: FD %d: commSetSelect on read icapRespModReadReply.\n",
++ fd);
++ commSetSelect(fd, COMM_SELECT_READ, icapRespModReadReply, icap, 0);
++#if 1
++ commSetTimeout(fd, Config.Timeout.read, icapReadTimeout, icap);
++ commSetDefer(fd, fwdCheckDeferRead, icap->respmod.entry);
++#else
++ if (icap->flags.wait_for_preview_reply || icap->flags.http_server_eof) {
++ /*
++ * Set the read timeout only after all data has been sent
++ * or we are waiting for a preview response
++ * If the ICAP server does not return any data till all data
++ * has been sent, we are likely to hit the timeout for large
++ * HTTP bodies
++ */
++ commSetTimeout(fd, Config.Timeout.read, icapReadTimeout, icap);
++ }
++#endif
++ }
++}
++
++void
++icapConnectOver(int fd, int status, void *data)
++{
++ ErrorState *err;
++ IcapStateData *icap = data;
++ debug(81, 3) ("icapConnectOver: FD %d, status=%d\n", fd, status);
++ icap->flags.connect_pending = 0;
++ if (status < 0) {
++ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
++ err->xerrno = errno;
++ err->request = requestLink(icap->request);
++ errorAppendEntry(icap->respmod.entry, err);
++ comm_close(fd);
++ debug(81, 3) ("icapConnectOver: status < 0, unreachable=1\n");
++ icapOptSetUnreachable(icap->current_service);
++ return;
++ }
++ fd_table[fd].pconn.uses++;
++ fd_table[fd].pconn.type = 2;
++ commSetSelect(fd, COMM_SELECT_READ, icapRespModReadReply, icap, 0);
++}
++
++
++
++IcapStateData *
++icapRespModStart(icap_service_t type, request_t * request, StoreEntry * entry,
++ http_state_flags http_flags)
++{
++ IcapStateData *icap = NULL;
++ CNCB *theCallback = NULL;
++ icap_service *service = NULL;
++
++ debug(81, 3) ("icapRespModStart: type=%d\n", (int) type);
++ assert(type >= 0 && type < ICAP_SERVICE_MAX);
++
++ service = icapService(type, request);
++ if (!service) {
++ debug(81, 3) ("icapRespModStart: no service found\n");
++ return NULL; /* no service found */
++ }
++ if (service->unreachable) {
++ if (service->bypass) {
++ debug(81,
++ 5)
++ ("icapRespModStart: BYPASS because service unreachable: %s\n",
++ service->uri);
++ return NULL;
++ } else {
++ debug(81,
++ 5)
++ ("icapRespModStart: ERROR because service unreachable: %s\n",
++ service->uri);
++ return (IcapStateData *) - 1;
++ }
++ }
++ switch (type) {
++ /* TODO: When we support more than ICAP_SERVICE_RESPMOD_PRECACHE, we needs to change
++ * this switch, because callbacks isn't keep */
++ case ICAP_SERVICE_RESPMOD_PRECACHE:
++ theCallback = icapConnectOver;
++ break;
++ default:
++ fatalf("icapRespModStart: unsupported service type '%s'\n",
++ icap_service_type_str[type]);
++ break;
++ }
++
++ icap = icapAllocate();
++ if (!icap) {
++ debug(81, 3) ("icapRespModStart: icapAllocate() failed\n");
++ return NULL;
++ }
++ icap->request = requestLink(request);
++ icap->respmod.entry = entry;
++ if (entry)
++ storeLockObject(entry);
++ icap->http_flags = http_flags;
++ memBufDefInit(&icap->respmod.buffer);
++ memBufDefInit(&icap->chunk_buf);
++
++ icap->current_service = service;
++ icap->preview_size = service->preview;
++
++ /*
++ * Don't create socket to the icap server now, but only for the first
++ * packet receive from the http server. This will resolve all timeout
++ * between the web server and icap server.
++ */
++ debug(81, 3) ("icapRespModStart: setting connect_requested to 0\n");
++ icap->flags.connect_requested = 0;
++
++ /*
++ * make a copy the HTTP response that we send to the ICAP server in
++ * case it turns out to be a 204
++ */
++#ifdef SUPPORT_ICAP_204
++ icap->flags.copy_response = 1;
++#elif ICAP_PREVIEW
++ if (preview_size < 0 || !Config.icapcfg.preview_enable)
++ icap->flags.copy_response = 0;
++ else
++ icap->flags.copy_response = 1;
++#else
++ icap->flags.copy_response = 0;
++#endif
++
++ statCounter.icap.all.requests++;
++ debug(81, 3) ("icapRespModStart: returning %p\n", icap);
++ return icap;
++}
++
++static int
++icapHttpReplyHdrState(IcapStateData * icap)
++{
++ assert(icap);
++ if (NULL == icap->httpState)
++ return 0;
++ return icap->httpState->reply_hdr_state;
++}
++
++static void
++icapProcessHttpReplyHeader(IcapStateData * icap, const char *buf, int size)
++{
++ if (NULL == icap->httpState) {
++ icap->httpState = cbdataAlloc(HttpStateData);
++ icap->httpState->request = requestLink(icap->request);
++ icap->httpState->orig_request = requestLink(icap->request);
++ icap->httpState->entry = icap->respmod.entry;
++ storeLockObject(icap->httpState->entry); /* lock it */
++ }
++ httpProcessReplyHeader(icap->httpState, buf, size);
++ if (2 == icap->httpState->reply_hdr_state)
++ EBIT_CLR(icap->httpState->entry->flags, ENTRY_FWD_HDR_WAIT);
++}
++
++/*
++ * icapRespModKeepAliveOrClose
++ *
++ * Called when we are done reading from the ICAP server.
++ * Either close the connection or keep it open for a future
++ * transaction.
++ */
++static void
++icapRespModKeepAliveOrClose(IcapStateData * icap)
++{
++ int fd = icap->icap_fd;
++ if (fd < 0)
++ return;
++ debug(81, 3) ("%s:%d FD %d looks good, keeping alive\n", __FILE__, __LINE__,
++ fd);
++ commSetDefer(fd, NULL, NULL);
++ commSetTimeout(fd, -1, NULL, NULL);
++ commSetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0);
++ comm_remove_close_handler(fd, icapStateFree, icap);
++ icap->icap_fd = -1;
++ if (!icap->flags.keep_alive) {
++ debug(81, 3) ("%s:%d keep_alive not set, closing\n", __FILE__,
++ __LINE__);
++ comm_close(fd);
++ return;
++ } else {
++ pconnPush(fd, icap->current_service->hostname, icap->current_service->port, NULL, NULL, 0);
++ }
++}
++
++
++
++/*
++ * copied from httpPconnTransferDone
++ *
++ */
++static int
++icapPconnTransferDone(int fd, IcapStateData * icap)
++{
++ debug(81, 3) ("icapPconnTransferDone: FD %d\n", fd);
++ /*
++ * Be careful with 204 responses. Normally we are done when we
++ * see the zero-end chunk, but that won't happen for 204s, so we
++ * use an EOF indicator on the HTTP side instead.
++ */
++ if (icap->flags.no_content && icap->flags.http_server_eof) {
++ debug(81, 5) ("icapPconnTransferDone: no content, ret 1\n");
++ return 1;
++ }
++ if (icapHttpReplyHdrState(icap) != 2) {
++ debug(81,
++ 5) ("icapPconnTransferDone: didn't see end of HTTP hdrs, ret 0\n");
++ return 0;
++ }
++ if (icap->enc.null_body > -1) {
++ debug(81, 5) ("icapPconnTransferDone: no message body, ret 1\n");
++ return 1;
++ }
++ if (icap->chunk_size == -2) { //AI: was != -2 ; and change content with bottom
++ /* zero end chunk reached */
++ debug(81, 5) ("icapPconnTransferDone: got zero end chunk\n");
++ return 1;
++ }
++ debug(81, 5) ("icapPconnTransferDone: didnt get zero end chunk yet\n"); //AI: change with second top condition
++
++ return 0;
++}
++
++static int
++icapExpectedHttpReplyHdrSize(IcapStateData * icap)
++{
++ if (icap->enc.res_body > -1 && icap->enc.res_hdr > -1)
++ return (icap->enc.res_body - icap->enc.res_hdr);
++ if (icap->enc.null_body > -1 && icap->enc.res_hdr > -1)
++ return icap->enc.null_body - icap->enc.res_hdr;
++ /*The case we did not get res_hdr ..... */
++ if (icap->enc.res_body > -1)
++ return icap->enc.res_body;
++ if (icap->enc.null_body > -1)
++ return icap->enc.null_body;
++ return -1;
++}
++
++/*
++ * copied from httpReadReply()
++ *
++ * by the time this is called, the ICAP headers have already
++ * been read.
++ */
++void
++icapReadReply(int fd, void *data)
++{
++ IcapStateData *icap = data;
++ StoreEntry *entry = icap->respmod.entry;
++ const request_t *request = icap->request;
++ int len;
++ debug(81, 5) ("icapReadReply: FD %d: icap %p.\n", fd, data);
++ if (icap->flags.no_content && !icap->flags.http_server_eof) { //AI
++
++ return;
++ }
++ if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
++ comm_close(fd);
++ return;
++ }
++ errno = 0;
++ statCounter.syscalls.sock.reads++;
++ len = memBufRead(fd, &icap->chunk_buf);
++ debug(81, 5) ("icapReadReply: FD %d: len %d.\n", fd, len);
++ if (len > 0) {
++ fd_bytes(fd, len, FD_READ);
++ kb_incr(&statCounter.icap.all.kbytes_in, len);
++ commSetTimeout(fd, Config.Timeout.read, icapReadTimeout, icap);
++ if (icap->chunk_buf.size < icap->chunk_buf.capacity) {
++ *(icap->chunk_buf.buf + icap->chunk_buf.size) = '\0';
++ debug(81, 9) ("{%s}\n", icap->chunk_buf.buf);
++ }
++ }
++ if (len <= 0) {
++ debug(81, 2) ("icapReadReply: FD %d: read failure: %s.\n",
++ fd, xstrerror());
++ if (ignoreErrno(errno)) {
++ debug(81, 2) ("icapReadReply: FD %d: ignored errno\n", fd);
++ commSetSelect(fd, COMM_SELECT_READ, icapReadReply, icap, 0);
++ } else if (entry->mem_obj->inmem_hi == 0) {
++ ErrorState *err;
++ debug(81, 2) ("icapReadReply: FD %d: generating error page\n", fd);
++ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
++ err->request = requestLink((request_t *) request);
++ err->xerrno = errno;
++ errorAppendEntry(entry, err);
++ comm_close(fd);
++ } else {
++ debug(81, 2) ("icapReadReply: FD %d: just calling comm_close()\n",
++ fd);
++ comm_close(fd);
++ }
++ return;
++ }
++ if (icapReadReply2(icap) < 0)
++ comm_close(fd);
++}
++
++static int
++icapReadReply2(IcapStateData * icap)
++{
++ StoreEntry *entry = icap->respmod.entry;
++ const request_t *request = icap->request;
++ debug(81, 3) ("icapReadReply2\n");
++ if (icap->chunk_buf.size == 0 && entry->mem_obj->inmem_hi == 0) {
++ ErrorState *err;
++ err = errorCon(ERR_ZERO_SIZE_OBJECT, HTTP_SERVICE_UNAVAILABLE);
++ err->xerrno = errno;
++ err->request = requestLink((request_t *) request);
++ errorAppendEntry(entry, err);
++ icap->flags.http_server_eof = 1;
++ return -1;
++ }
++ if (icap->chunk_buf.size == 0) {
++ /* Retrieval done. */
++ if (icapHttpReplyHdrState(icap) < 2)
++ icapProcessHttpReplyHeader(icap, icap->chunk_buf.buf,
++ icap->chunk_buf.size);
++ icap->flags.http_server_eof = 1;
++ icapReadReply3(icap);
++ return 0;
++ }
++ if (icapHttpReplyHdrState(icap) == 0) {
++ int expect = icapExpectedHttpReplyHdrSize(icap);
++ int so_far = icap->http_header_bytes_read_so_far;
++ int needed = expect - so_far;
++ debug(81, 3) ("expect=%d\n", expect);
++ debug(81, 3) ("so_far=%d\n", so_far);
++ debug(81, 3) ("needed=%d\n", needed);
++ assert(needed < 0 || needed >= 0);
++ if (0 > expect) {
++ icapProcessHttpReplyHeader(icap,
++ icap->chunk_buf.buf, icap->chunk_buf.size);
++ } else if (0 == expect) {
++ /*
++ * this icap reply doesn't give us new HTTP headers
++ * so we must copy them from our copy
++ */
++ debug(81, 1) ("WARNING: untested code at %s:%d\n", __FILE__,
++ __LINE__);
++ if (icap->respmod.req_hdr_copy.size) { /*For HTTP 0.9 we do not have headers */
++ storeAppend(entry,
++ icap->respmod.req_hdr_copy.buf,
++ icap->respmod.req_hdr_copy.size);
++ }
++ icapProcessHttpReplyHeader(icap, icap->chunk_buf.buf,
++ icap->chunk_buf.size);
++ assert(icapHttpReplyHdrState(icap) == 2);
++ icap->chunk_size = 0; /*we are ready to read chunks of data now.... */
++ } else if (needed) {
++ icapProcessHttpReplyHeader(icap,
++ icap->chunk_buf.buf, icap->chunk_buf.size);
++ if (icap->chunk_buf.size >= needed) {
++ storeAppend(entry, icap->chunk_buf.buf, needed);
++ so_far += needed;
++ xmemmove(icap->chunk_buf.buf,
++ icap->chunk_buf.buf + needed,
++ icap->chunk_buf.size - needed);
++ icap->chunk_buf.size -= needed;
++ assert(icapHttpReplyHdrState(icap) == 2);
++ icap->chunk_size = 0;
++ } else {
++ /*
++ * We don't have the full HTTP reply headers yet, so keep
++ * the partial reply buffered in 'chunk_buf' and wait
++ * for more.
++ */
++ debug(81, 3) ("We don't have full Http headers.Schedule a new read\n");
++ commSetSelect(icap->icap_fd, COMM_SELECT_READ, icapReadReply, icap, 0);
++ }
++ }
++ icap->http_header_bytes_read_so_far = so_far;
++ }
++ debug(81, 3) ("%s:%d: icap->chunk_buf.size=%d\n", __FILE__, __LINE__,
++ (int) icap->chunk_buf.size);
++ debug(81, 3) ("%s:%d: flags.no_content=%d\n", __FILE__, __LINE__,
++ icap->flags.no_content);
++ if (icap->flags.no_content) {
++ /* data from http.c is not chunked */
++ if (!EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
++ debug(81, 3) ("copying %d bytes from chunk_buf to entry\n",
++ icap->chunk_buf.size);
++ storeAppend(entry, icap->chunk_buf.buf, icap->chunk_buf.size);
++ icap->chunk_buf.size = 0;
++ }
++ } else if (2 == icapHttpReplyHdrState(icap)) {
++ if (icap->chunk_buf.size)
++ icapParseChunkedBody(icap, (STRCB *) storeAppend, entry);
++ }
++ icapReadReply3(icap);
++ return 0;
++}
++
++static void
++icapReadReply3(IcapStateData * icap)
++{
++ StoreEntry *entry = icap->respmod.entry;
++ int fd = icap->icap_fd;
++ debug(81, 3) ("icapReadReply3\n");
++ if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
++ debug(81, 3) ("icapReadReply3: Entry Aborded\n");
++ if (icap->flags.no_content)
++ icapStateFree(-1, icap);
++ else
++ comm_close(fd);
++ } else if (icapPconnTransferDone(fd, icap)) {
++ storeComplete(entry);
++ if (icap->flags.no_content)
++ icapStateFree(-1, icap);
++ else {
++ icapRespModKeepAliveOrClose(icap);
++ icapStateFree(-1, icap);
++ }
++ } else if (!icap->flags.no_content) {
++ /* Wait for EOF condition */
++ commSetSelect(fd, COMM_SELECT_READ, icapReadReply, icap, 0);
++ debug(81,
++ 3)
++ ("icapReadReply3: Going to read mode data throught icapReadReply\n");
++ } else {
++ debug(81, 3) ("icapReadReply3: Nothing\n");
++ }
++}
+Index: src/main.c
+===================================================================
+RCS file: /cvsroot/squid/squid/src/main.c,v
+retrieving revision 1.67
+retrieving revision 1.45.4.7
+diff -p -u -b -r1.67 -r1.45.4.7
+--- src/main.c 30 Jul 2006 23:52:54 -0000 1.67
++++ src/main.c 3 Aug 2006 17:16:04 -0000 1.45.4.7
+@@ -391,6 +391,9 @@ mainReconfigure(void)
+ #else
+ idnsShutdown();
+ #endif
++#ifdef HS_FEAT_ICAP
++ icapClose();
++#endif
+ redirectShutdown();
+ locationRewriteShutdown();
+ authenticateShutdown();
+@@ -422,6 +425,9 @@ mainReconfigure(void)
+ #endif
+ redirectInit();
+ locationRewriteInit();
++#ifdef HS_FEAT_ICAP
++ icapInit();
++#endif
+ authenticateInit(&Config.authConfig);
+ externalAclInit();
+ #if USE_WCCP
+@@ -565,6 +571,9 @@ mainInitialize(void)
+ redirectInit();
+ locationRewriteInit();
+ errorMapInit();
++#ifdef HS_FEAT_ICAP
++ icapInit();
++#endif
+ authenticateInit(&Config.authConfig);
+ externalAclInit();
+ useragentOpenLog();
+Index: src/mem.c
+===================================================================
+RCS file: /cvsroot/squid/squid/src/mem.c,v
+retrieving revision 1.27
+retrieving revision 1.24.4.3
+diff -p -u -b -r1.27 -r1.24.4.3
+--- src/mem.c 20 May 2006 22:50:55 -0000 1.27
++++ src/mem.c 26 May 2006 18:21:32 -0000 1.24.4.3
+@@ -353,6 +353,13 @@ memInit(void)
+ memDataInit(MEM_TLV, "storeSwapTLV", sizeof(tlv), 0);
+ memDataInit(MEM_SWAP_LOG_DATA, "storeSwapLogData", sizeof(storeSwapLogData), 0);
+
++#ifdef HS_FEAT_ICAP
++ memDataInit(MEM_ICAP_OPT_DATA, "IcapOptData", sizeof(IcapOptData), 0);
++ memDataInit(MEM_ICAP_SERVICE_LIST, "icap_service_list", sizeof(icap_service_list), 0);
++ memDataInit(MEM_ICAP_CLASS, "icap_class", sizeof(icap_class), 0);
++ memDataInit(MEM_ICAP_ACCESS, "icap_access", sizeof(icap_access), 0);
++#endif
++
+ /* init string pools */
+ for (i = 0; i < mem_str_pool_count; i++) {
+ StrPools[i].pool = memPoolCreate(StrPoolsAttrs[i].name, StrPoolsAttrs[i].obj_size);
+Index: src/mk-string-arrays.pl
+===================================================================
+RCS file: /cvsroot/squid/squid/src/mk-string-arrays.pl,v
+retrieving revision 1.2
+retrieving revision 1.2.180.1
+diff -p -u -b -r1.2 -r1.2.180.1
+--- src/mk-string-arrays.pl 23 Oct 2000 15:04:21 -0000 1.2
++++ src/mk-string-arrays.pl 17 May 2006 17:58:01 -0000 1.2.180.1
+@@ -16,6 +16,7 @@ $pat{'err_type'} = "err_type_str";
+ $pat{'icp_opcode'} = "icp_opcode_str";
+ $pat{'swap_log_op'} = "swap_log_op_str";
+ $pat{'lookup_t'} = "lookup_t_str";
++$pat{'icap_service_t'} = "icap_service_type_str";
+
+ $state = 0; # start state
+ while (<>) {
+Index: src/pconn.c
+===================================================================
+RCS file: /cvsroot/squid/squid/src/pconn.c,v
+retrieving revision 1.10
+retrieving revision 1.9.4.2
+diff -p -u -b -r1.10 -r1.9.4.2
+--- src/pconn.c 22 May 2006 22:06:12 -0000 1.10
++++ src/pconn.c 26 May 2006 18:21:32 -0000 1.9.4.2
+@@ -46,6 +46,9 @@ struct _pconn {
+ #define PCONN_HIST_SZ (1<<16)
+ int client_pconn_hist[PCONN_HIST_SZ];
+ int server_pconn_hist[PCONN_HIST_SZ];
++#ifdef HS_FEAT_ICAP
++int icap_server_pconn_hist[PCONN_HIST_SZ];
++#endif
+
+ static PF pconnRead;
+ static PF pconnTimeout;
+@@ -169,6 +172,20 @@ pconnHistDump(StoreEntry * e)
+ continue;
+ storeAppendPrintf(e, "\t%4d %9d\n", i, server_pconn_hist[i]);
+ }
++#ifdef HS_FEAT_ICAP
++ storeAppendPrintf(e,
++ "\n"
++ "ICAP-server persistent connection counts:\n"
++ "\n"
++ "\treq/\n"
++ "\tconn count\n"
++ "\t---- ---------\n");
++ for (i = 0; i < PCONN_HIST_SZ; i++) {
++ if (icap_server_pconn_hist[i] == 0)
++ continue;
++ storeAppendPrintf(e, "\t%4d %9d\n", i, icap_server_pconn_hist[i]);
++ }
++#endif
+ }
+
+ /* ========== PUBLIC FUNCTIONS ============================================ */
+@@ -183,6 +200,9 @@ pconnInit(void)
+ for (i = 0; i < PCONN_HIST_SZ; i++) {
+ client_pconn_hist[i] = 0;
+ server_pconn_hist[i] = 0;
++#ifdef HS_FEAT_ICAP
++ icap_server_pconn_hist[i] = 0;
++#endif
+ }
+ pconn_data_pool = memPoolCreate("pconn_data", sizeof(struct _pconn));
+ pconn_fds_pool = memPoolCreate("pconn_fds", PCONN_FDS_SZ * sizeof(int));
+@@ -265,11 +285,15 @@ pconnHistCount(int what, int i)
+ {
+ if (i >= PCONN_HIST_SZ)
+ i = PCONN_HIST_SZ - 1;
+- /* what == 0 for client, 1 for server */
++ /* what == 0 for client, 1 for server, 2 for ICAP server */
+ if (what == 0)
+ client_pconn_hist[i]++;
+ else if (what == 1)
+ server_pconn_hist[i]++;
++#ifdef HS_FEAT_ICAP
++ else if (what == 2)
++ icap_server_pconn_hist[i]++;
++#endif
+ else
+ assert(0);
+ }
+Index: src/protos.h
+===================================================================
+RCS file: /cvsroot/squid/squid/src/protos.h,v
+retrieving revision 1.118
+retrieving revision 1.74.4.8
+diff -p -u -b -r1.118 -r1.74.4.8
+--- src/protos.h 30 Jul 2006 23:52:54 -0000 1.118
++++ src/protos.h 3 Aug 2006 17:16:05 -0000 1.74.4.8
+@@ -295,6 +295,8 @@ extern void whoisStart(FwdState *);
+ /* http.c */
+ extern int httpCachable(method_t);
+ extern void httpStart(FwdState *);
++extern void httpParseReplyHeaders(const char *, http_reply *);
++extern void httpProcessReplyHeader(HttpStateData *, const char *, int);
+ extern int httpBuildRequestPrefix(request_t * request,
+ request_t * orig_request,
+ StoreEntry * entry,
+@@ -617,6 +619,7 @@ extern void memBufVPrintf(MemBuf * mb, c
+ extern FREE *memBufFreeFunc(MemBuf * mb);
+ /* puts report on MemBuf _module_ usage into mb */
+ extern void memBufReport(MemBuf * mb);
++extern int memBufRead(int fd, MemBuf * mb);
+
+ extern char *mime_get_header(const char *mime, const char *header);
+ extern char *mime_get_header_field(const char *mime, const char *name, const char *prefix);
+@@ -1409,4 +1412,53 @@ void storeLocateVaryDone(VaryData * data
+ void storeLocateVary(StoreEntry * e, int offset, const char *vary_data, String accept_encoding, STLVCB * callback, void *cbdata);
+ void storeAddVary(const char *url, const char *log_url, const method_t method, const cache_key * key, const char *etag, const char *vary, const char *vary_headers, const char *accept_encoding);
+
++#ifdef HS_FEAT_ICAP
++/*
++ * icap_common.c
++ */
++void icapInit(void);
++void icapClose(void);
++void icapParseEncapsulated(IcapStateData *, const char *, const char *);
++icap_service *icapService(icap_service_t, request_t *);
++int icapConnect(IcapStateData *, CNCB *);
++IcapStateData *icapAllocate(void);
++PF icapStateFree;
++PF icapConnectTimeout;
++PF icapReadTimeout;
++icap_service_t icapServiceToType(const char *);
++const char *icapServiceToStr(const icap_service_t);
++int icapCheckAcl(clientHttpRequest *);
++size_t icapLineLength(const char *, int);
++int icapReadHeader(int, IcapStateData *, int *);
++int icapFindHeader(const char *, const char *, const char **, const char **);
++int icapParseKeepAlive(const IcapStateData *, const char *, const char *);
++void icapSetKeepAlive(IcapStateData * icap, const char *hdrs);
++size_t icapParseChunkedBody(IcapStateData *, STRCB *, void *);
++void icapAddAuthUserHeader(MemBuf *, auth_user_request_t *);
++int icapParseStatusLine(const char *, int, int *, int *, const char **);
++
++/*
++ * icap_respmod.c
++ */
++IcapStateData *icapRespModStart(icap_service_t, request_t *, StoreEntry *, http_state_flags);
++void icapSendRespMod(IcapStateData *, char *, int, int);
++CNCB icapConnectOver;
++
++/*
++ * icap_reqmod.c
++ */
++IcapStateData *icapReqModStart(icap_service*, const char *, request_t *, int, struct timeval, struct in_addr, void *);
++
++/* icap_opt.c */
++void icapOptInit(void);
++void icapOptShutdown(void);
++void icapOptSetUnreachable(icap_service * s);
++
++/* X-Server-IP support */
++void icapAddOriginIP(MemBuf *, const char *);
++
++/* for debugging purposes only */
++void dump_icap_config(IcapConfig * cfg);
++#endif
++
+ #endif /* SQUID_PROTOS_H */
+Index: src/squid.h
+===================================================================
+RCS file: /cvsroot/squid/squid/src/squid.h,v
+retrieving revision 1.34
+retrieving revision 1.24.8.5
+diff -p -u -b -r1.34 -r1.24.8.5
+--- src/squid.h 8 Jun 2006 13:51:37 -0000 1.34
++++ src/squid.h 12 Jun 2006 17:56:59 -0000 1.24.8.5
+@@ -38,6 +38,14 @@
+ #include "config.h"
+
+ /*
++ * experimental defines for ICAP
++ */
++#ifdef HS_FEAT_ICAP
++#define ICAP_PREVIEW 1
++#define SUPPORT_ICAP_204 0
++#endif
++
++/*
+ * On some systems, FD_SETSIZE is set to something lower than the
+ * actual number of files which can be opened. IRIX is one case,
+ * NetBSD is another. So here we increase FD_SETSIZE to our
+Index: src/stat.c
+===================================================================
+RCS file: /cvsroot/squid/squid/src/stat.c,v
+retrieving revision 1.34
+retrieving revision 1.26.8.7
+diff -p -u -b -r1.34 -r1.26.8.7
+--- src/stat.c 29 Jul 2006 17:50:57 -0000 1.34
++++ src/stat.c 3 Aug 2006 17:16:06 -0000 1.26.8.7
+@@ -787,6 +787,17 @@ statAvgDump(StoreEntry * sentry, int min
+ storeAppendPrintf(sentry, "server.other.kbytes_out = %f/sec\n",
+ XAVG(server.other.kbytes_out.kb));
+
++#ifdef HS_FEAT_ICAP
++ storeAppendPrintf(sentry, "icap.all.requests = %f/sec\n",
++ XAVG(icap.all.requests));
++ storeAppendPrintf(sentry, "icap.all.errors = %f/sec\n",
++ XAVG(icap.all.errors));
++ storeAppendPrintf(sentry, "icap.all.kbytes_in = %f/sec\n",
++ XAVG(icap.all.kbytes_in.kb));
++ storeAppendPrintf(sentry, "icap.all.kbytes_out = %f/sec\n",
++ XAVG(icap.all.kbytes_out.kb));
++#endif
++
+ storeAppendPrintf(sentry, "icp.pkts_sent = %f/sec\n",
+ XAVG(icp.pkts_sent));
+ storeAppendPrintf(sentry, "icp.pkts_recv = %f/sec\n",
+@@ -1171,6 +1182,17 @@ statCountersDump(StoreEntry * sentry)
+ storeAppendPrintf(sentry, "server.other.kbytes_out = %d\n",
+ (int) f->server.other.kbytes_out.kb);
+
++#if HS_FEAT_ICAP
++ storeAppendPrintf(sentry, "icap.all.requests = %d\n",
++ (int) f->icap.all.requests);
++ storeAppendPrintf(sentry, "icap.all.errors = %d\n",
++ (int) f->icap.all.errors);
++ storeAppendPrintf(sentry, "icap.all.kbytes_in = %d\n",
++ (int) f->icap.all.kbytes_in.kb);
++ storeAppendPrintf(sentry, "icap.all.kbytes_out = %d\n",
++ (int) f->icap.all.kbytes_out.kb);
++#endif
++
+ storeAppendPrintf(sentry, "icp.pkts_sent = %d\n",
+ f->icp.pkts_sent);
+ storeAppendPrintf(sentry, "icp.pkts_recv = %d\n",
+@@ -1471,8 +1493,6 @@ statClientRequests(StoreEntry * s)
+ storeAppendPrintf(s, "\tme: %s:%d\n",
+ inet_ntoa(conn->me.sin_addr),
+ ntohs(conn->me.sin_port));
+- storeAppendPrintf(s, "\tnrequests: %d\n",
+- conn->nrequests);
+ storeAppendPrintf(s, "\tdefer: n %d, until %ld\n",
+ conn->defer.n, (long int) conn->defer.until);
+ }
+Index: src/store.c
+===================================================================
+RCS file: /cvsroot/squid/squid/src/store.c,v
+retrieving revision 1.35
+retrieving revision 1.21.10.7
+diff -p -u -b -r1.35 -r1.21.10.7
+--- src/store.c 17 Jul 2006 02:51:31 -0000 1.35
++++ src/store.c 22 Jul 2006 14:12:02 -0000 1.21.10.7
+@@ -1088,8 +1088,17 @@ storeAppend(StoreEntry * e, const char *
+ MemObject *mem = e->mem_obj;
+ assert(mem != NULL);
+ assert(len >= 0);
+- assert(e->store_status == STORE_PENDING);
+ mem->refresh_timestamp = squid_curtime;
++ debug(20, 3) ("storeAppend: '%s'\n", storeKeyText(e->hash.key));
++ if (e->store_status != STORE_PENDING) {
++ /*
++ * if we're not STORE_PENDING, then probably we got aborted
++ * and there should be NO clients on this entry
++ */
++ assert(EBIT_TEST(e->flags, ENTRY_ABORTED));
++ assert(e->mem_obj->nclients == 0);
++ return;
++ }
+ if (len) {
+ debug(20, 5) ("storeAppend: appending %d bytes for '%s'\n",
+ len,
+Index: src/structs.h
+===================================================================
+RCS file: /cvsroot/squid/squid/src/structs.h,v
+retrieving revision 1.126
+retrieving revision 1.81.4.8
+diff -p -u -b -r1.126 -r1.81.4.8
+--- src/structs.h 30 Jul 2006 23:52:55 -0000 1.126
++++ src/structs.h 3 Aug 2006 17:16:06 -0000 1.81.4.8
+@@ -423,6 +423,23 @@ struct _RemovalPolicySettings {
+ wordlist *args;
+ };
+
++#if HS_FEAT_ICAP
++struct _IcapConfig {
++ int onoff;
++ int preview_enable;
++ icap_service *service_head;
++ icap_class *class_head;
++ icap_access *access_head;
++ int preview_size;
++ int check_interval;
++ int send_client_ip;
++ int send_server_ip;
++ int send_auth_user;
++ char *auth_scheme;
++};
++
++#endif /* HS_FEAT_ICAP */
++
+ struct _SquidConfig {
+ struct {
+ squid_off_t maxSize;
+@@ -808,6 +825,9 @@ struct _SquidConfig {
+ #endif
+ time_t refresh_stale_window;
+ int umask;
++#ifdef HS_FEAT_ICAP
++ IcapConfig icapcfg;
++#endif
+ };
+
+ struct _SquidConfig2 {
+@@ -879,6 +899,10 @@ struct _fde {
+ comm_pending write_pending;
+ squid_off_t bytes_read;
+ squid_off_t bytes_written;
++ struct {
++ int uses;
++ int type;
++ } pconn;
+ int uses; /* ie # req's over persistent conn */
+ struct _fde_disk {
+ DWCB *wrt_handle;
+@@ -1075,6 +1099,131 @@ struct _http_state_flags {
+ unsigned int originpeer:1;
+ };
+
++#ifdef HS_FEAT_ICAP
++struct _IcapStateData {
++ request_t *request;
++ http_state_flags http_flags;
++ HttpStateData *httpState; /* needed to parse HTTP headers only */
++ int icap_fd;
++ int sc;
++ icap_service *current_service;
++ MemBuf icap_hdr;
++ struct {
++ int res_hdr;
++ int res_body;
++ int req_hdr;
++ int req_body;
++ int opt_body;
++ int null_body;
++ } enc;
++ int bytes_to_gobble;
++ int chunk_size;
++ MemBuf chunk_buf;
++ int preview_size;
++ squid_off_t fake_content_length;
++ int http_header_bytes_read_so_far;
++ struct {
++ const char *uri; /* URI for REQMODs */
++ int client_fd;
++ struct timeval start; /* for logging */
++ struct in_addr log_addr; /* for logging */
++ int hdr_state;
++ MemBuf hdr_buf;
++ void *client_cookie;
++ struct {
++ MemBuf buf;
++ CBCB *callback;
++ void *callback_data;
++ char *callback_buf;
++ size_t callback_bufsize;
++ squid_off_t bytes_read;
++ } http_entity;
++ } reqmod;
++ struct {
++ StoreEntry *entry;
++ MemBuf buffer;
++ MemBuf req_hdr_copy; /* XXX barf */
++ MemBuf resp_copy; /* XXX barf^max */
++ squid_off_t res_body_sz;
++ } respmod;
++ struct {
++ unsigned int connect_requested:1;
++ unsigned int connect_pending:1;
++ unsigned int write_pending:1;
++ unsigned int keep_alive:1;
++ unsigned int http_server_eof:1;
++ unsigned int send_zero_chunk:1;
++ unsigned int got_reply:1;
++ unsigned int wait_for_reply:1;
++ unsigned int wait_for_preview_reply:1;
++ unsigned int preview_done:1;
++ unsigned int copy_response:1;
++ unsigned int no_content:1;
++ unsigned int reqmod_http_entity_eof:1;
++ } flags;
++};
++
++struct _icap_service {
++ icap_service *next;
++ char *name; /* name to be used when referencing ths service */
++ char *uri; /* uri of server/service to use */
++ char *type_name; /* {req|resp}mod_{pre|post}cache */
++
++ char *hostname;
++ unsigned short int port;
++ char *resource;
++ icap_service_t type; /* parsed type */
++ icap_method_t method;
++ ushort bypass; /* flag: bypass allowed */
++ ushort unreachable; /* flag: set to 1 if options request fails */
++ IcapOptData *opt; /* temp data needed during opt request */
++ struct {
++ unsigned int allow_204:1;
++ unsigned int need_x_client_ip:1;
++ unsigned int need_x_server_ip:1;
++ unsigned int need_x_authenticated_user:1;
++ } flags;
++ int preview;
++ String istag;
++ String transfer_preview;
++ String transfer_ignore;
++ String transfer_complete;
++ int max_connections;
++ int options_ttl;
++ int keep_alive;
++};
++
++struct _icap_service_list {
++ icap_service_list *next;
++ icap_service *services[16];
++ int nservices; /* Number of services already used */
++ int last_service_used; /* Last services used, use to do a round robin */
++};
++
++struct _icap_class {
++ icap_class *next;
++ char *name;
++ wordlist *services;
++ icap_service_list *isl;
++ ushort hidden; /* for unnamed classes */
++};
++
++struct _icap_access {
++ icap_access *next;
++ char *service_name;
++ icap_class *class;
++ acl_access *access;
++};
++
++struct _IcapOptData {
++ char *buf;
++ off_t offset;
++ size_t size;
++ off_t headlen;
++};
++
++#endif
++
+ struct _HttpStateData {
+ StoreEntry *entry;
+ request_t *request;
+@@ -1086,10 +1235,14 @@ struct _HttpStateData {
+ int fd;
+ http_state_flags flags;
+ FwdState *fwd;
++#ifdef HS_FEAT_ICAP
++ struct _IcapStateData *icap_writer;
++#endif
+ char *body_buf;
+ int body_buf_sz;
+ };
+
++
+ struct _icpUdpData {
+ struct sockaddr_in address;
+ void *msg;
+@@ -1198,6 +1351,7 @@ struct _clientHttpRequest {
+ unsigned int internal:1;
+ unsigned int done_copying:1;
+ unsigned int purging:1;
++ unsigned int did_icap_reqmod:1;
+ unsigned int hit:1;
+ } flags;
+ struct {
+@@ -1206,6 +1360,9 @@ struct _clientHttpRequest {
+ } redirect;
+ dlink_node active;
+ squid_off_t maxBodySize;
++#if HS_FEAT_ICAP
++ IcapStateData *icap_reqmod;
++#endif
+ };
+
+ struct _ConnStateData {
+@@ -1873,6 +2030,9 @@ struct _request_t {
+ unsigned int done_etag:1; /* We have done clientProcessETag on this, don't attempt it again */
+ char *urlgroup; /* urlgroup, returned by redirectors */
+ char *peer_domain; /* Configured peer forceddomain */
++#if HS_FEAT_ICAP
++ icap_class *class;
++#endif
+ BODY_HANDLER *body_reader;
+ void *body_reader_data;
+ String extacl_log; /* String to be used for access.log purposes */
+@@ -1989,7 +2149,11 @@ struct _StatCounters {
+ kb_t kbytes_in;
+ kb_t kbytes_out;
+ } all , http, ftp, other;
+- } server;
++ }
++#if HS_FEAT_ICAP
++ icap,
++#endif
++ server;
+ struct {
+ int pkts_sent;
+ int queries_sent;
+Index: src/typedefs.h
+===================================================================
+RCS file: /cvsroot/squid/squid/src/typedefs.h,v
+retrieving revision 1.39
+retrieving revision 1.32.4.6
+diff -p -u -b -r1.39 -r1.32.4.6
+--- src/typedefs.h 30 Jul 2006 23:52:55 -0000 1.39
++++ src/typedefs.h 3 Aug 2006 17:16:07 -0000 1.32.4.6
+@@ -136,6 +136,15 @@ typedef struct _HttpHeaderStat HttpHeade
+ typedef struct _HttpBody HttpBody;
+ typedef struct _HttpReply HttpReply;
+ typedef struct _HttpStateData HttpStateData;
++#ifdef HS_FEAT_ICAP
++typedef struct _IcapStateData IcapStateData;
++typedef struct _IcapConfig IcapConfig;
++typedef struct _icap_service icap_service;
++typedef struct _icap_service_list icap_service_list;
++typedef struct _icap_class icap_class;
++typedef struct _icap_access icap_access;
++typedef struct _IcapOptData IcapOptData;
++#endif
+ typedef struct _icpUdpData icpUdpData;
+ typedef struct _clientHttpRequest clientHttpRequest;
+ typedef struct _ConnStateData ConnStateData;
+Index: src/url.c
+===================================================================
+RCS file: /cvsroot/squid/squid/src/url.c,v
+retrieving revision 1.17
+retrieving revision 1.14.10.4
+diff -p -u -b -r1.17 -r1.14.10.4
+--- src/url.c 17 Jun 2006 23:51:19 -0000 1.17
++++ src/url.c 28 Jun 2006 21:12:01 -0000 1.14.10.4
+@@ -103,6 +103,9 @@ const char *ProtocolStr[] =
+ "whois",
+ "internal",
+ "https",
++#ifdef HS_FEAT_ICAP
++ "icap",
++#endif
+ "TOTAL"
+ };
+
+@@ -217,6 +220,10 @@ urlParseProtocol(const char *s)
+ return PROTO_WHOIS;
+ if (strcasecmp(s, "internal") == 0)
+ return PROTO_INTERNAL;
++#ifdef HS_FEAT_ICAP
++ if (strcasecmp(s, "icap") == 0)
++ return PROTO_ICAP;
++#endif
+ return PROTO_NONE;
+ }
+
+@@ -240,6 +247,10 @@ urlDefaultPort(protocol_t p)
+ return CACHE_HTTP_PORT;
+ case PROTO_WHOIS:
+ return 43;
++#ifdef HS_FEAT_ICAP
++ case PROTO_ICAP:
++ return 1344;
++#endif
+ default:
+ return 0;
+ }
diff --git a/www/squid27/files/patch-changeset.10801 b/www/squid27/files/patch-changeset.10801
deleted file mode 100644
index f73e5dbf7b4d..000000000000
--- a/www/squid27/files/patch-changeset.10801
+++ /dev/null
@@ -1,284 +0,0 @@
----------------------
-PatchSet 10801
-Date: 2006/07/04 21:51:15
-Author: hno
-Branch: HEAD
-Tag: (none)
-Log:
-Bug #1650: transparent interception "Unable to forward this request at this time"
-
-this patch clears up some confusion between accelerated and transparently
-intercepted requests, clearly separating the two cases.
-
-With this patch the --enable-auth-on-acceleration is removed again as it
-no longer serves any purpose as there no longer is any conflict between
-the processing accelerated and transparently intercepted requests.
-
-Members:
- configure:1.388->1.389
- configure.in:1.384->1.385
- include/autoconf.h.in:1.153->1.154
- src/acl.c:1.303->1.304
- src/client_side.c:1.657->1.658
- src/structs.h:1.489->1.490
-
-Index: squid/configure
-===================================================================
-RCS file: /cvsroot/squid/squid/configure,v
-retrieving revision 1.388
-retrieving revision 1.389
-diff -u -r1.388 -r1.389
---- configure 1 Jul 2006 18:42:04 -0000 1.388
-+++ configure 4 Jul 2006 21:51:15 -0000 1.389
-@@ -907,8 +907,6 @@
- --enable-forw-via-db Enable Forw/Via database
- --enable-cache-digests Use Cache Digests
- see http://www.squid-cache.org/FAQ/FAQ-16.html
-- --enable-auth-on-acceleration
-- Enable authentication in accelerators
- --enable-default-err-language=lang
- Select default language for Error pages (see
- errors directory)
-@@ -4220,20 +4218,6 @@
-
- fi;
-
--# Check whether --enable-auth-on-acceleration or --disable-auth-on-acceleration was given.
--if test "${enable_auth_on_acceleration+set}" = set; then
-- enableval="$enable_auth_on_acceleration"
-- if test "$enableval" = "yes" ; then
-- echo "AUTH_ON_ACCELERATION enabled"
--
--cat >>confdefs.h <<\_ACEOF
--#define AUTH_ON_ACCELERATION 1
--_ACEOF
--
-- fi
--
--fi;
--
- # Check whether --enable-default-err-language or --disable-default-err-language was given.
- if test "${enable_default_err_language+set}" = set; then
- enableval="$enable_default_err_language"
-Index: squid/configure.in
-===================================================================
-RCS file: /cvsroot/squid/squid/configure.in,v
-retrieving revision 1.384
-retrieving revision 1.385
-diff -u -r1.384 -r1.385
---- configure.in 1 Jul 2006 18:41:21 -0000 1.384
-+++ configure.in 4 Jul 2006 21:51:15 -0000 1.385
-@@ -736,15 +736,6 @@
- fi
- ])
-
--AC_ARG_ENABLE(auth-on-acceleration,
--[ --enable-auth-on-acceleration
-- Enable authentication in accelerators],
--[ if test "$enableval" = "yes" ; then
-- echo "AUTH_ON_ACCELERATION enabled"
-- AC_DEFINE(AUTH_ON_ACCELERATION, 1, [Enable authentication support in accelerators])
-- fi
--])
--
- dnl Select Default Error language
- AC_ARG_ENABLE(default-err-language,
- [ --enable-default-err-language=lang
-Index: squid/include/autoconf.h.in
-===================================================================
-RCS file: /cvsroot/squid/squid/include/autoconf.h.in,v
-retrieving revision 1.153
-retrieving revision 1.154
-diff -u -r1.153 -r1.154
---- include/autoconf.h.in 21 Jun 2006 20:33:46 -0000 1.153
-+++ include/autoconf.h.in 4 Jul 2006 21:51:16 -0000 1.154
-@@ -3,9 +3,6 @@
- /* Defines how many threads aufs uses for I/O */
- #undef AUFS_IO_THREADS
-
--/* Enable authentication support in accelerators */
--#undef AUTH_ON_ACCELERATION
--
- /* If you are upset that the cachemgr.cgi form comes up with the hostname
- field blank, then define this to getfullhostname() */
- #undef CACHEMGR_HOSTNAME
-Index: squid/src/acl.c
-===================================================================
-RCS file: /cvsroot/squid/squid/src/acl.c,v
-retrieving revision 1.303
-retrieving revision 1.304
-diff -u -r1.303 -r1.304
---- src/acl.c 17 Jun 2006 23:31:03 -0000 1.303
-+++ src/acl.c 4 Jul 2006 21:51:16 -0000 1.304
-@@ -400,6 +400,10 @@
- type->accelerated = 1;
- continue;
- }
-+ if (strcmp(t, "transparent") == 0) {
-+ type->transparent = 1;
-+ continue;
-+ }
- if (strcmp(t, "internal") == 0) {
- type->internal = 1;
- continue;
-@@ -1679,6 +1683,8 @@
- {
- if (type->accelerated && request->flags.accelerated)
- return 1;
-+ if (type->transparent && request->flags.transparent)
-+ return 1;
- if (type->internal && request->flags.internal)
- return 1;
- return 0;
-@@ -1691,20 +1697,15 @@
- http_hdr_type headertype;
- if (NULL == r) {
- return -1;
-- } else if (!r->flags.accelerated) {
-- /* Proxy authorization on proxy requests */
-- headertype = HDR_PROXY_AUTHORIZATION;
-- } else if (r->flags.internal) {
-- /* WWW authorization on accelerated internal requests */
-- headertype = HDR_AUTHORIZATION;
-- } else {
--#if AUTH_ON_ACCELERATION
-+ } else if (r->flags.accelerated) {
- /* WWW authorization on accelerated requests */
- headertype = HDR_AUTHORIZATION;
--#else
-- debug(28, 1) ("aclAuthenticated: authentication not applicable on accelerated requests.\n");
-+ } else if (r->flags.transparent) {
-+ debug(28, 1) ("aclAuthenticated: authentication not applicable on transparently intercepted requests.\n");
- return -1;
--#endif
-+ } else {
-+ /* Proxy authorization on proxy requests */
-+ headertype = HDR_PROXY_AUTHORIZATION;
- }
- /* get authed here */
- /* Note: this fills in checklist->auth_user_request when applicable (auth incomplete) */
-@@ -2911,6 +2912,8 @@
- wordlistAdd(&W, "accelerated");
- if (type->internal)
- wordlistAdd(&W, "internal");
-+ if (type->transparent)
-+ wordlistAdd(&W, "transparent");
- return W;
- }
-
-Index: squid/src/client_side.c
-===================================================================
-RCS file: /cvsroot/squid/squid/src/client_side.c,v
-retrieving revision 1.657
-retrieving revision 1.658
-diff -u -r1.657 -r1.658
---- src/client_side.c 4 Jul 2006 00:06:11 -0000 1.657
-+++ src/client_side.c 4 Jul 2006 21:51:17 -0000 1.658
-@@ -3482,7 +3482,7 @@
- /*
- * Deny loops when running in accelerator/transproxy mode.
- */
-- if (http->flags.accel && r->flags.loopdetect) {
-+ if (r->flags.loopdetect && (http->flags.accel || http->flags.transparent)) {
- http->al.http.code = HTTP_FORBIDDEN;
- err = errorCon(ERR_ACCESS_DENIED, HTTP_FORBIDDEN);
- err->request = requestLink(http->orig_request);
-@@ -3684,15 +3684,19 @@
- if (method == METHOD_CONNECT) {
- if (http_ver.major < 1)
- goto invalid_request;
-+ if (conn->port->accel)
-+ goto invalid_request;
- } else if (*url == '/')
- accel:{
- int vhost = conn->port->vhost || conn->port->transparent;
-- int vport = conn->port->vport || conn->transparent;
-+ int vport = conn->port->vport;
-+ int accel = conn->port->accel;
-+ if (!vport && conn->transparent)
-+ vport = ntohs(conn->me.sin_port);
- if (Config.onoff.global_internal_static && conn->port->accel && internalCheck(url)) {
- /* prepend our name & port */
- http->uri = xstrdup(internalStoreUri("", url));
- http->flags.internal = 1;
-- http->flags.accel = 1;
- debug(33, 5) ("INTERNAL REWRITE: '%s'\n", http->uri);
- } else if (vhost && (t = mime_get_header(req_hdr, "Host"))) {
- url_sz = strlen(url) + 32 + Config.appendDomainLen +
-@@ -3724,14 +3728,14 @@
- /* prepend our name & port */
- http->uri = xstrdup(internalStoreUri("", url));
- http->flags.internal = 1;
-- http->flags.accel = 1;
- debug(33, 5) ("INTERNAL REWRITE: '%s'\n", http->uri);
- } else {
- goto invalid_request;
- }
-- http->flags.accel = 1;
-- } else if (conn->transparent) {
-- http->flags.accel = 1;
-+ if (accel)
-+ http->flags.accel = 1;
-+ else if (conn->port->transparent)
-+ http->flags.transparent = 1;
- } else if (conn->port->accel) {
- http->flags.accel = 1;
- if (!conn->port->vhost) {
-@@ -3743,9 +3747,6 @@
- url = (char *) "/";
- goto accel;
- }
-- } else {
-- /* Proxy request */
-- http->flags.accel = 0;
- }
- if (!http->uri) {
- /* No special rewrites have been applied above, use the
-@@ -3753,7 +3754,6 @@
- url_sz = strlen(url) + Config.appendDomainLen + 5;
- http->uri = xcalloc(url_sz, 1);
- strcpy(http->uri, url);
-- http->flags.accel = 0;
- }
- if (!stringHasCntl(http->uri))
- http->log_uri = xstrndup(http->uri, MAX_URL);
-@@ -3989,6 +3989,7 @@
- request->flags.tproxy = conn->port->tproxy;
- #endif
- request->flags.accelerated = http->flags.accel;
-+ request->flags.transparent = http->flags.transparent;
- /*
- * cache the Content-length value in request_t.
- */
-Index: squid/src/structs.h
-===================================================================
-RCS file: /cvsroot/squid/squid/src/structs.h,v
-retrieving revision 1.489
-retrieving revision 1.490
-diff -u -r1.489 -r1.490
---- src/structs.h 30 Jun 2006 21:23:05 -0000 1.489
-+++ src/structs.h 4 Jul 2006 21:51:18 -0000 1.490
-@@ -346,6 +346,7 @@
-
- struct _acl_request_type {
- unsigned int accelerated:1;
-+ unsigned int transparent:1;
- unsigned int internal:1;
- };
-
-@@ -1190,6 +1191,7 @@
- AccessLogEntry al;
- struct {
- unsigned int accel:1;
-+ unsigned int transparent:1;
- unsigned int internal:1;
- unsigned int done_copying:1;
- unsigned int purging:1;
-@@ -1785,6 +1787,7 @@
- unsigned int nocache_hack:1; /* for changing/ignoring no-cache requests */
- #endif
- unsigned int accelerated:1;
-+ unsigned int transparent:1;
- unsigned int internal:1;
- unsigned int body_sent:1;
- unsigned int reset_tcp:1;
diff --git a/www/squid27/files/patch-src-client_side.c b/www/squid27/files/patch-src-client_side.c
deleted file mode 100644
index 3c9eed63c572..000000000000
--- a/www/squid27/files/patch-src-client_side.c
+++ /dev/null
@@ -1,16 +0,0 @@
---- ./src/client_side.c.orig Thu Jul 6 11:44:18 2006
-+++ ./src/client_side.c Thu Jul 6 11:52:07 2006
-@@ -4490,6 +4490,13 @@
- return -1;
- }
- }
-+#elif IPFW_TRANSPARENT
-+static int inline
-+clientNatLookup(ConnStateData * conn)
-+{
-+ static time_t last_reported = 0;
-+ return 0;
-+}
- #else
- static int inline
- clientNatLookup(ConnStateData * conn)