diff -ruN squid-2.6.STABLE5/icap-2_6.patch squid-icap-2.6.STABLE5/icap-2_6.patch
--- squid-2.6.STABLE5/icap-2_6.patch 2006-12-10 18:50:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/icap-2_6.patch 1970-01-01 02:00:00.000000000 +0200
@@ -1,7065 +0,0 @@
-This patch is generated from the icap-2_6 branch of HEAD in squid
-Tue Nov 28 01:15:46 2006 GMT
-See http://devel.squid-cache.org/
-
-Index: squid/configure.in
-diff -u squid/configure.in:1.165 squid/configure.in:1.87.4.12
---- squid/configure.in:1.165 Fri Nov 3 05:54:34 2006
-+++ squid/configure.in Fri Nov 3 10:47:04 2006
-@@ -530,6 +530,17 @@
- fi
- ])
-
-+dnl Enable ICAP Support
-+AM_CONDITIONAL(USE_ICAP, false)
-+AC_ARG_ENABLE(icap-support,
-+[ --enable-icap-support Enable ICAP client capability],
-+[ if test "$enableval" = "yes" ; then
-+ echo "ICAP support enabled"
-+ AC_DEFINE(HS_FEAT_ICAP, 1, [Content filtering via ICAP servers.])
-+ AM_CONDITIONAL(USE_ICAP, true)
-+ fi
-+])
-+
- dnl This is a developer only option. Developers know how to set defines
- dnl
- dnl AC_ARG_ENABLE(mem-gen-trace,
-@@ -2346,6 +2357,8 @@
- srand48 \
- srandom \
- statfs \
-+ strnstr \
-+ strcasestr \
- strsep \
- strtoll \
- sysconf \
-@@ -2450,6 +2463,16 @@
- AM_CONDITIONAL(NEED_OWN_SNPRINTF, true)
- fi
-
-+AM_CONDITIONAL(NEED_OWN_STRNSTR, false)
-+if test "$ac_cv_func_strnstr" = "no" || test "$ac_cv_func_vstrnstr" = "no" ; then
-+ AM_CONDITIONAL(NEED_OWN_STRNSTR, true)
-+fi
-+
-+AM_CONDITIONAL(NEED_OWN_STRCASESTR, false)
-+if test "$ac_cv_func_strcasestr" = "no" || test "$ac_cv_func_vstrcasestr" = "no"; then
-+ AM_CONDITIONAL(NEED_OWN_STRCASESTR, true)
-+fi
-+
- AM_CONDITIONAL(NEED_OWN_STRSEP, false)
- if test "$ac_cv_func_strsep" = "no" ; then
- AM_CONDITIONAL(NEED_OWN_STRSEP, true)
-Index: squid/errors/list
-diff -u squid/errors/list:1.4 squid/errors/list:1.4.10.1
---- squid/errors/list:1.4 Fri Apr 28 04:10:45 2006
-+++ squid/errors/list Wed May 17 10:57:59 2006
-@@ -28,3 +28,4 @@
- ERR_URN_RESOLVE
- ERR_WRITE_ERROR
- ERR_ZERO_SIZE_OBJECT
-+ERR_ICAP_FAILURE
-Index: squid/errors/Bulgarian/ERR_ICAP_FAILURE
-diff -u /dev/null squid/errors/Bulgarian/ERR_ICAP_FAILURE:1.1.14.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/errors/Bulgarian/ERR_ICAP_FAILURE Wed May 17 10:57:59 2006
-@@ -0,0 +1,31 @@
-+
-+
-+ERROR: The requested URL could not be retrieved
-+
-+
-+ERROR
-+The requested URL could not be retrieved
-+
-+
-+While attempting to retrieve the URL:
-+%U
-+
-+the following error was encountered:
-+
-+-
-+
-+ICAP protocol error.
-+
-+
-+
-+
-+
-+Some aspect of the ICAP communication failed. Possible problems:
-+
-+- ICAP server is not reachable.
-+
- Illegal response from ICAP server.
-+
-+
-+
-+Your cache administrator is %w.
-+
-Index: squid/errors/Catalan/ERR_ICAP_FAILURE
-diff -u /dev/null squid/errors/Catalan/ERR_ICAP_FAILURE:1.1.14.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/errors/Catalan/ERR_ICAP_FAILURE Wed May 17 10:57:59 2006
-@@ -0,0 +1,31 @@
-+
-+
-+ERROR: The requested URL could not be retrieved
-+
-+
-+ERROR
-+The requested URL could not be retrieved
-+
-+
-+While attempting to retrieve the URL:
-+%U
-+
-+the following error was encountered:
-+
-+-
-+
-+ICAP protocol error.
-+
-+
-+
-+
-+
-+Some aspect of the ICAP communication failed. Possible problems:
-+
-+- ICAP server is not reachable.
-+
- Illegal response from ICAP server.
-+
-+
-+
-+Your cache administrator is %w.
-+
-Index: squid/errors/Czech/ERR_ICAP_FAILURE
-diff -u /dev/null squid/errors/Czech/ERR_ICAP_FAILURE:1.1.14.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/errors/Czech/ERR_ICAP_FAILURE Wed May 17 10:57:59 2006
-@@ -0,0 +1,31 @@
-+
-+
-+ERROR: The requested URL could not be retrieved
-+
-+
-+ERROR
-+The requested URL could not be retrieved
-+
-+
-+While attempting to retrieve the URL:
-+%U
-+
-+the following error was encountered:
-+
-+-
-+
-+ICAP protocol error.
-+
-+
-+
-+
-+
-+Some aspect of the ICAP communication failed. Possible problems:
-+
-+- ICAP server is not reachable.
-+
- Illegal response from ICAP server.
-+
-+
-+
-+Your cache administrator is %w.
-+
-Index: squid/errors/Danish/ERR_ICAP_FAILURE
-diff -u /dev/null squid/errors/Danish/ERR_ICAP_FAILURE:1.1.14.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/errors/Danish/ERR_ICAP_FAILURE Wed May 17 10:57:59 2006
-@@ -0,0 +1,31 @@
-+
-+
-+ERROR: The requested URL could not be retrieved
-+
-+
-+ERROR
-+The requested URL could not be retrieved
-+
-+
-+While attempting to retrieve the URL:
-+%U
-+
-+the following error was encountered:
-+
-+-
-+
-+ICAP protocol error.
-+
-+
-+
-+
-+
-+Some aspect of the ICAP communication failed. Possible problems:
-+
-+- ICAP server is not reachable.
-+
- Illegal response from ICAP server.
-+
-+
-+
-+Your cache administrator is %w.
-+
-Index: squid/errors/Dutch/ERR_ICAP_FAILURE
-diff -u /dev/null squid/errors/Dutch/ERR_ICAP_FAILURE:1.1.14.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/errors/Dutch/ERR_ICAP_FAILURE Wed May 17 10:57:59 2006
-@@ -0,0 +1,31 @@
-+
-+
-+ERROR: The requested URL could not be retrieved
-+
-+
-+ERROR
-+The requested URL could not be retrieved
-+
-+
-+While attempting to retrieve the URL:
-+%U
-+
-+the following error was encountered:
-+
-+-
-+
-+ICAP protocol error.
-+
-+
-+
-+
-+
-+Some aspect of the ICAP communication failed. Possible problems:
-+
-+- ICAP server is not reachable.
-+
- Illegal response from ICAP server.
-+
-+
-+
-+Your cache administrator is %w.
-+
-Index: squid/errors/English/ERR_ICAP_FAILURE
-diff -u /dev/null squid/errors/English/ERR_ICAP_FAILURE:1.1.14.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/errors/English/ERR_ICAP_FAILURE Wed May 17 10:57:59 2006
-@@ -0,0 +1,31 @@
-+
-+
-+ERROR: The requested URL could not be retrieved
-+
-+
-+ERROR
-+The requested URL could not be retrieved
-+
-+
-+While attempting to retrieve the URL:
-+%U
-+
-+the following error was encountered:
-+
-+-
-+
-+ICAP protocol error.
-+
-+
-+
-+
-+
-+Some aspect of the ICAP communication failed. Possible problems:
-+
-+- ICAP server is not reachable.
-+
- Illegal response from ICAP server.
-+
-+
-+
-+Your cache administrator is %w.
-+
-Index: squid/errors/Estonian/ERR_ICAP_FAILURE
-diff -u /dev/null squid/errors/Estonian/ERR_ICAP_FAILURE:1.1.14.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/errors/Estonian/ERR_ICAP_FAILURE Wed May 17 10:57:59 2006
-@@ -0,0 +1,31 @@
-+
-+
-+ERROR: The requested URL could not be retrieved
-+
-+
-+ERROR
-+The requested URL could not be retrieved
-+
-+
-+While attempting to retrieve the URL:
-+%U
-+
-+the following error was encountered:
-+
-+-
-+
-+ICAP protocol error.
-+
-+
-+
-+
-+
-+Some aspect of the ICAP communication failed. Possible problems:
-+
-+- ICAP server is not reachable.
-+
- Illegal response from ICAP server.
-+
-+
-+
-+Your cache administrator is %w.
-+
-Index: squid/errors/Finnish/ERR_ICAP_FAILURE
-diff -u /dev/null squid/errors/Finnish/ERR_ICAP_FAILURE:1.1.14.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/errors/Finnish/ERR_ICAP_FAILURE Wed May 17 10:57:59 2006
-@@ -0,0 +1,31 @@
-+
-+
-+ERROR: The requested URL could not be retrieved
-+
-+
-+ERROR
-+The requested URL could not be retrieved
-+
-+
-+While attempting to retrieve the URL:
-+%U
-+
-+the following error was encountered:
-+
-+-
-+
-+ICAP protocol error.
-+
-+
-+
-+
-+
-+Some aspect of the ICAP communication failed. Possible problems:
-+
-+- ICAP server is not reachable.
-+
- Illegal response from ICAP server.
-+
-+
-+
-+Your cache administrator is %w.
-+
-Index: squid/errors/French/ERR_ICAP_FAILURE
-diff -u /dev/null squid/errors/French/ERR_ICAP_FAILURE:1.1.14.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/errors/French/ERR_ICAP_FAILURE Wed May 17 10:57:59 2006
-@@ -0,0 +1,31 @@
-+
-+
-+ERROR: The requested URL could not be retrieved
-+
-+
-+ERROR
-+The requested URL could not be retrieved
-+
-+
-+While attempting to retrieve the URL:
-+%U
-+
-+the following error was encountered:
-+
-+-
-+
-+ICAP protocol error.
-+
-+
-+
-+
-+
-+Some aspect of the ICAP communication failed. Possible problems:
-+
-+- ICAP server is not reachable.
-+
- Illegal response from ICAP server.
-+
-+
-+
-+Your cache administrator is %w.
-+
-Index: squid/errors/German/ERR_ICAP_FAILURE
-diff -u /dev/null squid/errors/German/ERR_ICAP_FAILURE:1.1.14.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/errors/German/ERR_ICAP_FAILURE Wed May 17 10:57:59 2006
-@@ -0,0 +1,33 @@
-+
-+
-+FEHLER: Der angeforderte URL konnte nicht geholt werden
-+
-+
-+FEHLER
-+Der angeforderte URL konnte nicht geholt werden
-+
-+
-+Während des Versuches, den URL
-+%U
-+
-+
-+zu laden, trat der folgende Fehler auf:
-+
-+-
-+
-+ICAP-Protokollfehler
-+
-+
-+
-+
-+
-+Es trat ein Problem bei der ICAP-Kommunikation auf. Mögliche Gründe:
-+
-+- Nicht erreichbarer ICAP-Server
-+
- Ungültige Antwort vom ICAP-Server
-+
-+
-+
-+
-+Ihr Cache Administrator ist %w.
-+
-Index: squid/errors/Greek/ERR_ICAP_FAILURE
-diff -u /dev/null squid/errors/Greek/ERR_ICAP_FAILURE:1.1.12.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/errors/Greek/ERR_ICAP_FAILURE Wed May 17 10:57:59 2006
-@@ -0,0 +1,31 @@
-+
-+
-+ERROR: The requested URL could not be retrieved
-+
-+
-+ERROR
-+The requested URL could not be retrieved
-+
-+
-+While attempting to retrieve the URL:
-+%U
-+
-+the following error was encountered:
-+
-+-
-+
-+ICAP protocol error.
-+
-+
-+
-+
-+
-+Some aspect of the ICAP communication failed. Possible problems:
-+
-+- ICAP server is not reachable.
-+
- Illegal response from ICAP server.
-+
-+
-+
-+Your cache administrator is %w.
-+
-Index: squid/errors/Hebrew/ERR_ICAP_FAILURE
-diff -u /dev/null squid/errors/Hebrew/ERR_ICAP_FAILURE:1.1.14.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/errors/Hebrew/ERR_ICAP_FAILURE Wed May 17 10:57:59 2006
-@@ -0,0 +1,31 @@
-+
-+
-+ERROR: The requested URL could not be retrieved
-+
-+
-+ERROR
-+The requested URL could not be retrieved
-+
-+
-+While attempting to retrieve the URL:
-+%U
-+
-+the following error was encountered:
-+
-+-
-+
-+ICAP protocol error.
-+
-+
-+
-+
-+
-+Some aspect of the ICAP communication failed. Possible problems:
-+
-+- ICAP server is not reachable.
-+
- Illegal response from ICAP server.
-+
-+
-+
-+Your cache administrator is %w.
-+
-Index: squid/errors/Hungarian/ERR_ICAP_FAILURE
-diff -u /dev/null squid/errors/Hungarian/ERR_ICAP_FAILURE:1.1.14.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/errors/Hungarian/ERR_ICAP_FAILURE Wed May 17 10:57:59 2006
-@@ -0,0 +1,31 @@
-+
-+
-+ERROR: The requested URL could not be retrieved
-+
-+
-+ERROR
-+The requested URL could not be retrieved
-+
-+
-+While attempting to retrieve the URL:
-+%U
-+
-+the following error was encountered:
-+
-+-
-+
-+ICAP protocol error.
-+
-+
-+
-+
-+
-+Some aspect of the ICAP communication failed. Possible problems:
-+
-+- ICAP server is not reachable.
-+
- Illegal response from ICAP server.
-+
-+
-+
-+Your cache administrator is %w.
-+
-Index: squid/errors/Italian/ERR_ICAP_FAILURE
-diff -u /dev/null squid/errors/Italian/ERR_ICAP_FAILURE:1.1.14.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/errors/Italian/ERR_ICAP_FAILURE Wed May 17 10:57:59 2006
-@@ -0,0 +1,31 @@
-+
-+
-+ERROR: The requested URL could not be retrieved
-+
-+
-+ERROR
-+The requested URL could not be retrieved
-+
-+
-+While attempting to retrieve the URL:
-+%U
-+
-+the following error was encountered:
-+
-+-
-+
-+ICAP protocol error.
-+
-+
-+
-+
-+
-+Some aspect of the ICAP communication failed. Possible problems:
-+
-+- ICAP server is not reachable.
-+
- Illegal response from ICAP server.
-+
-+
-+
-+Your cache administrator is %w.
-+
-Index: squid/errors/Japanese/ERR_ICAP_FAILURE
-diff -u /dev/null squid/errors/Japanese/ERR_ICAP_FAILURE:1.1.14.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/errors/Japanese/ERR_ICAP_FAILURE Wed May 17 10:57:59 2006
-@@ -0,0 +1,31 @@
-+
-+
-+ERROR: The requested URL could not be retrieved
-+
-+
-+ERROR
-+The requested URL could not be retrieved
-+
-+
-+While attempting to retrieve the URL:
-+%U
-+
-+the following error was encountered:
-+
-+-
-+
-+ICAP protocol error.
-+
-+
-+
-+
-+
-+Some aspect of the ICAP communication failed. Possible problems:
-+
-+- ICAP server is not reachable.
-+
- Illegal response from ICAP server.
-+
-+
-+
-+Your cache administrator is %w.
-+
-Index: squid/errors/Korean/ERR_ICAP_FAILURE
-diff -u /dev/null squid/errors/Korean/ERR_ICAP_FAILURE:1.1.14.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/errors/Korean/ERR_ICAP_FAILURE Wed May 17 10:58:00 2006
-@@ -0,0 +1,31 @@
-+
-+
-+ERROR: The requested URL could not be retrieved
-+
-+
-+ERROR
-+The requested URL could not be retrieved
-+
-+
-+While attempting to retrieve the URL:
-+%U
-+
-+the following error was encountered:
-+
-+-
-+
-+ICAP protocol error.
-+
-+
-+
-+
-+
-+Some aspect of the ICAP communication failed. Possible problems:
-+
-+- ICAP server is not reachable.
-+
- Illegal response from ICAP server.
-+
-+
-+
-+Your cache administrator is %w.
-+
-Index: squid/errors/Lithuanian/ERR_ICAP_FAILURE
-diff -u /dev/null squid/errors/Lithuanian/ERR_ICAP_FAILURE:1.1.14.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/errors/Lithuanian/ERR_ICAP_FAILURE Wed May 17 10:58:00 2006
-@@ -0,0 +1,31 @@
-+
-+
-+ERROR: The requested URL could not be retrieved
-+
-+
-+ERROR
-+The requested URL could not be retrieved
-+
-+
-+While attempting to retrieve the URL:
-+%U
-+
-+the following error was encountered:
-+
-+-
-+
-+ICAP protocol error.
-+
-+
-+
-+
-+
-+Some aspect of the ICAP communication failed. Possible problems:
-+
-+- ICAP server is not reachable.
-+
- Illegal response from ICAP server.
-+
-+
-+
-+Your cache administrator is %w.
-+
-Index: squid/errors/Polish/ERR_ICAP_FAILURE
-diff -u /dev/null squid/errors/Polish/ERR_ICAP_FAILURE:1.1.14.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/errors/Polish/ERR_ICAP_FAILURE Wed May 17 10:58:00 2006
-@@ -0,0 +1,31 @@
-+
-+
-+ERROR: The requested URL could not be retrieved
-+
-+
-+ERROR
-+The requested URL could not be retrieved
-+
-+
-+While attempting to retrieve the URL:
-+%U
-+
-+the following error was encountered:
-+
-+-
-+
-+ICAP protocol error.
-+
-+
-+
-+
-+
-+Some aspect of the ICAP communication failed. Possible problems:
-+
-+- ICAP server is not reachable.
-+
- Illegal response from ICAP server.
-+
-+
-+
-+Your cache administrator is %w.
-+
-Index: squid/errors/Portuguese/ERR_ICAP_FAILURE
-diff -u /dev/null squid/errors/Portuguese/ERR_ICAP_FAILURE:1.1.14.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/errors/Portuguese/ERR_ICAP_FAILURE Wed May 17 10:58:00 2006
-@@ -0,0 +1,31 @@
-+
-+
-+ERROR: The requested URL could not be retrieved
-+
-+
-+ERROR
-+The requested URL could not be retrieved
-+
-+
-+While attempting to retrieve the URL:
-+%U
-+
-+the following error was encountered:
-+
-+-
-+
-+ICAP protocol error.
-+
-+
-+
-+
-+
-+Some aspect of the ICAP communication failed. Possible problems:
-+
-+- ICAP server is not reachable.
-+
- Illegal response from ICAP server.
-+
-+
-+
-+Your cache administrator is %w.
-+
-Index: squid/errors/Romanian/ERR_ICAP_FAILURE
-diff -u /dev/null squid/errors/Romanian/ERR_ICAP_FAILURE:1.1.14.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/errors/Romanian/ERR_ICAP_FAILURE Wed May 17 10:58:00 2006
-@@ -0,0 +1,31 @@
-+
-+
-+ERROR: The requested URL could not be retrieved
-+
-+
-+ERROR
-+The requested URL could not be retrieved
-+
-+
-+While attempting to retrieve the URL:
-+%U
-+
-+the following error was encountered:
-+
-+-
-+
-+ICAP protocol error.
-+
-+
-+
-+
-+
-+Some aspect of the ICAP communication failed. Possible problems:
-+
-+- ICAP server is not reachable.
-+
- Illegal response from ICAP server.
-+
-+
-+
-+Your cache administrator is %w.
-+
-Index: squid/errors/Russian-1251/ERR_ICAP_FAILURE
-diff -u /dev/null squid/errors/Russian-1251/ERR_ICAP_FAILURE:1.1.14.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/errors/Russian-1251/ERR_ICAP_FAILURE Wed May 17 10:58:00 2006
-@@ -0,0 +1,31 @@
-+
-+
-+ERROR: The requested URL could not be retrieved
-+
-+
-+ERROR
-+The requested URL could not be retrieved
-+
-+
-+While attempting to retrieve the URL:
-+%U
-+
-+the following error was encountered:
-+
-+-
-+
-+ICAP protocol error.
-+
-+
-+
-+
-+
-+Some aspect of the ICAP communication failed. Possible problems:
-+
-+- ICAP server is not reachable.
-+
- Illegal response from ICAP server.
-+
-+
-+
-+Your cache administrator is %w.
-+
-Index: squid/errors/Russian-koi8-r/ERR_ICAP_FAILURE
-diff -u /dev/null squid/errors/Russian-koi8-r/ERR_ICAP_FAILURE:1.1.14.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/errors/Russian-koi8-r/ERR_ICAP_FAILURE Wed May 17 10:58:00 2006
-@@ -0,0 +1,31 @@
-+
-+
-+ERROR: The requested URL could not be retrieved
-+
-+
-+ERROR
-+The requested URL could not be retrieved
-+
-+
-+While attempting to retrieve the URL:
-+%U
-+
-+the following error was encountered:
-+
-+-
-+
-+ICAP protocol error.
-+
-+
-+
-+
-+
-+Some aspect of the ICAP communication failed. Possible problems:
-+
-+- ICAP server is not reachable.
-+
- Illegal response from ICAP server.
-+
-+
-+
-+Your cache administrator is %w.
-+
-Index: squid/errors/Serbian/ERR_ICAP_FAILURE
-diff -u /dev/null squid/errors/Serbian/ERR_ICAP_FAILURE:1.1.14.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/errors/Serbian/ERR_ICAP_FAILURE Wed May 17 10:58:00 2006
-@@ -0,0 +1,31 @@
-+
-+
-+ERROR: The requested URL could not be retrieved
-+
-+
-+ERROR
-+The requested URL could not be retrieved
-+
-+
-+While attempting to retrieve the URL:
-+%U
-+
-+the following error was encountered:
-+
-+-
-+
-+ICAP protocol error.
-+
-+
-+
-+
-+
-+Some aspect of the ICAP communication failed. Possible problems:
-+
-+- ICAP server is not reachable.
-+
- Illegal response from ICAP server.
-+
-+
-+
-+Your cache administrator is %w.
-+
-Index: squid/errors/Simplify_Chinese/ERR_ICAP_FAILURE
-diff -u /dev/null squid/errors/Simplify_Chinese/ERR_ICAP_FAILURE:1.1.14.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/errors/Simplify_Chinese/ERR_ICAP_FAILURE Wed May 17 10:58:00 2006
-@@ -0,0 +1,31 @@
-+
-+
-+ERROR: The requested URL could not be retrieved
-+
-+
-+ERROR
-+The requested URL could not be retrieved
-+
-+
-+While attempting to retrieve the URL:
-+%U
-+
-+the following error was encountered:
-+
-+-
-+
-+ICAP protocol error.
-+
-+
-+
-+
-+
-+Some aspect of the ICAP communication failed. Possible problems:
-+
-+- ICAP server is not reachable.
-+
- Illegal response from ICAP server.
-+
-+
-+
-+Your cache administrator is %w.
-+
-Index: squid/errors/Slovak/ERR_ICAP_FAILURE
-diff -u /dev/null squid/errors/Slovak/ERR_ICAP_FAILURE:1.1.14.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/errors/Slovak/ERR_ICAP_FAILURE Wed May 17 10:58:00 2006
-@@ -0,0 +1,31 @@
-+
-+
-+ERROR: The requested URL could not be retrieved
-+
-+
-+ERROR
-+The requested URL could not be retrieved
-+
-+
-+While attempting to retrieve the URL:
-+%U
-+
-+the following error was encountered:
-+
-+-
-+
-+ICAP protocol error.
-+
-+
-+
-+
-+
-+Some aspect of the ICAP communication failed. Possible problems:
-+
-+- ICAP server is not reachable.
-+
- Illegal response from ICAP server.
-+
-+
-+
-+Your cache administrator is %w.
-+
-Index: squid/errors/Spanish/ERR_ICAP_FAILURE
-diff -u /dev/null squid/errors/Spanish/ERR_ICAP_FAILURE:1.1.14.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/errors/Spanish/ERR_ICAP_FAILURE Wed May 17 10:58:00 2006
-@@ -0,0 +1,31 @@
-+
-+
-+ERROR: The requested URL could not be retrieved
-+
-+
-+ERROR
-+The requested URL could not be retrieved
-+
-+
-+While attempting to retrieve the URL:
-+%U
-+
-+the following error was encountered:
-+
-+-
-+
-+ICAP protocol error.
-+
-+
-+
-+
-+
-+Some aspect of the ICAP communication failed. Possible problems:
-+
-+- ICAP server is not reachable.
-+
- Illegal response from ICAP server.
-+
-+
-+
-+Your cache administrator is %w.
-+
-Index: squid/errors/Swedish/ERR_ICAP_FAILURE
-diff -u /dev/null squid/errors/Swedish/ERR_ICAP_FAILURE:1.1.14.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/errors/Swedish/ERR_ICAP_FAILURE Wed May 17 10:58:00 2006
-@@ -0,0 +1,31 @@
-+
-+
-+ERROR: The requested URL could not be retrieved
-+
-+
-+ERROR
-+The requested URL could not be retrieved
-+
-+
-+While attempting to retrieve the URL:
-+%U
-+
-+the following error was encountered:
-+
-+-
-+
-+ICAP protocol error.
-+
-+
-+
-+
-+
-+Some aspect of the ICAP communication failed. Possible problems:
-+
-+- ICAP server is not reachable.
-+
- Illegal response from ICAP server.
-+
-+
-+
-+Your cache administrator is %w.
-+
-Index: squid/errors/Traditional_Chinese/ERR_ICAP_FAILURE
-diff -u /dev/null squid/errors/Traditional_Chinese/ERR_ICAP_FAILURE:1.1.14.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/errors/Traditional_Chinese/ERR_ICAP_FAILURE Wed May 17 10:58:00 2006
-@@ -0,0 +1,31 @@
-+
-+
-+ERROR: The requested URL could not be retrieved
-+
-+
-+ERROR
-+The requested URL could not be retrieved
-+
-+
-+While attempting to retrieve the URL:
-+%U
-+
-+the following error was encountered:
-+
-+-
-+
-+ICAP protocol error.
-+
-+
-+
-+
-+
-+Some aspect of the ICAP communication failed. Possible problems:
-+
-+- ICAP server is not reachable.
-+
- Illegal response from ICAP server.
-+
-+
-+
-+Your cache administrator is %w.
-+
-Index: squid/errors/Turkish/ERR_ICAP_FAILURE
-diff -u /dev/null squid/errors/Turkish/ERR_ICAP_FAILURE:1.1.14.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/errors/Turkish/ERR_ICAP_FAILURE Wed May 17 10:58:00 2006
-@@ -0,0 +1,31 @@
-+
-+
-+ERROR: The requested URL could not be retrieved
-+
-+
-+ERROR
-+The requested URL could not be retrieved
-+
-+
-+While attempting to retrieve the URL:
-+%U
-+
-+the following error was encountered:
-+
-+-
-+
-+ICAP protocol error.
-+
-+
-+
-+
-+
-+Some aspect of the ICAP communication failed. Possible problems:
-+
-+- ICAP server is not reachable.
-+
- Illegal response from ICAP server.
-+
-+
-+
-+Your cache administrator is %w.
-+
-Index: squid/include/util.h
-diff -u squid/include/util.h:1.15 squid/include/util.h:1.13.8.2
---- squid/include/util.h:1.15 Mon Sep 18 16:52:30 2006
-+++ squid/include/util.h Tue Sep 26 15:47:30 2006
-@@ -151,4 +151,12 @@
- extern int WIN32_Close_FD_Socket(int);
- #endif
-
-+#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: squid/lib/Makefile.am
-diff -u squid/lib/Makefile.am:1.10 squid/lib/Makefile.am:1.7.10.4
---- squid/lib/Makefile.am:1.10 Fri Sep 8 12:50:55 2006
-+++ squid/lib/Makefile.am Tue Sep 26 15:47:31 2006
-@@ -8,6 +8,19 @@
- else
- SNPRINTFSOURCE=
- endif
-+
-+if NEED_OWN_STRNSTR
-+STRNSTRSOURCE=strnstr.c
-+else
-+STRNSTRSOURCE=
-+endif
-+
-+if NEED_OWN_STRCASESTR
-+STRCASESTRSOURCE=strcasestr.c
-+else
-+STRCASESTRSOURCE=
-+endif
-+
- if NEED_OWN_STRSEP
- STRSEPSOURCE=strsep.c
- else
-@@ -63,6 +76,8 @@
- $(SNPRINTFSOURCE) \
- splay.c \
- Stack.c \
-+ $(STRNSTRSOURCE) \
-+ $(STRCASESTRSOURCE) \
- $(STRSEPSOURCE) \
- stub_memaccount.c \
- util.c \
-Index: squid/lib/strcasestr.c
-diff -u /dev/null squid/lib/strcasestr.c:1.1.14.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/lib/strcasestr.c Wed May 17 10:58:00 2006
-@@ -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
-+
-+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: squid/lib/strnstr.c
-diff -u /dev/null squid/lib/strnstr.c:1.1.14.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/lib/strnstr.c Wed May 17 10:58:00 2006
-@@ -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
-+#include
-+
-+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: squid/src/Makefile.am
-diff -u squid/src/Makefile.am:1.48 squid/src/Makefile.am:1.34.4.9
---- squid/src/Makefile.am:1.48 Sun Oct 29 16:51:32 2006
-+++ squid/src/Makefile.am Fri Nov 3 10:47:05 2006
-@@ -6,6 +6,12 @@
- # Uncomment and customize the following to suit your needs:
- #
-
-+if USE_ICAP
-+ICAPSOURCE = icap_common.c icap_reqmod.c icap_respmod.c icap_opt.c
-+else
-+ICAPSOURCE =
-+endif
-+
- if USE_DNSSERVER
- DNSSOURCE = dns.c
- DNSSERVER = dnsserver
-@@ -181,6 +187,7 @@
- HttpMsg.c \
- HttpReply.c \
- HttpRequest.c \
-+ $(ICAPSOURCE) \
- icmp.c \
- icp_v2.c \
- icp_v3.c \
-Index: squid/src/MemBuf.c
-diff -u squid/src/MemBuf.c:1.11 squid/src/MemBuf.c:1.9.10.4
---- squid/src/MemBuf.c:1.11 Tue Aug 15 17:53:02 2006
-+++ squid/src/MemBuf.c Mon Aug 21 12:48:09 2006
-@@ -341,3 +341,15 @@
- 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 > 0)
-+ mb->size += len;
-+ return len;
-+}
-Index: squid/src/cache_cf.c
-diff -u squid/src/cache_cf.c:1.85 squid/src/cache_cf.c:1.61.4.11
---- squid/src/cache_cf.c:1.85 Sat Sep 30 14:52:27 2006
-+++ squid/src/cache_cf.c Fri Nov 3 10:47:06 2006
-@@ -2385,6 +2385,587 @@
- 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 {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: squid/src/cbdata.c
-diff -u squid/src/cbdata.c:1.18 squid/src/cbdata.c:1.18.8.1
---- squid/src/cbdata.c:1.18 Fri May 12 15:51:56 2006
-+++ squid/src/cbdata.c Wed May 17 10:58:00 2006
-@@ -179,6 +179,10 @@
- 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: squid/src/cf.data.pre
-diff -u squid/src/cf.data.pre:1.158 squid/src/cf.data.pre:1.100.4.11
---- squid/src/cf.data.pre:1.158 Thu Oct 12 13:51:58 2006
-+++ squid/src/cf.data.pre Fri Nov 3 10:47:06 2006
-@@ -3184,7 +3184,6 @@
- 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
-@@ -3453,6 +3452,187 @@
- 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: squid/src/cf_gen_defines
-diff -u squid/src/cf_gen_defines:1.7 squid/src/cf_gen_defines:1.6.8.2
---- squid/src/cf_gen_defines:1.7 Wed May 31 12:51:14 2006
-+++ squid/src/cf_gen_defines Sun Jun 4 07:15:43 2006
-@@ -22,11 +22,12 @@
- 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] != "")
- DEFINE=define[$2]
-- else
-+ else
- DEFINE="-D" $2
- print "{\"" $2 "\", \"" DEFINE "\", "
- print "#if " $2
-Index: squid/src/client_side.c
-diff -u squid/src/client_side.c:1.147 squid/src/client_side.c:1.89.4.13
---- squid/src/client_side.c:1.147 Sat Sep 30 14:52:27 2006
-+++ squid/src/client_side.c Fri Nov 3 10:47:06 2006
-@@ -109,7 +109,7 @@
- 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 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 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 @@
- EBIT_TEST(r->cache_control->mask, CC_ONLY_IF_CACHED);
- }
-
--static StoreEntry *
-+StoreEntry *
- clientCreateStoreEntry(clientHttpRequest * h, method_t m, request_flags flags)
- {
- StoreEntry *e;
-@@ -638,6 +641,10 @@
- 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
-@@ -1372,11 +1379,22 @@
- *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;
-@@ -1393,8 +1411,9 @@
- authenticateAuthUserRequestUnlock(connState->auth_user_request);
- connState->auth_user_request = NULL;
- authenticateOnCloseConnection(connState);
-- memFreeBuf(connState->in.size, connState->in.buf);
-- pconnHistCount(0, connState->nrequests);
-+ if (connState->in.buf)
-+ memFreeBuf(connState->in.size, connState->in.buf);
-+/* pconnHistCount(0, connState->nrequests);*/
- if (connState->pinning.fd >= 0)
- comm_close(connState->pinning.fd);
- cbdataFree(connState);
-@@ -1592,7 +1611,7 @@
- }
- }
-
--static int
-+int
- clientCheckContentLength(request_t * r)
- {
- switch (r->method) {
-@@ -1611,7 +1630,7 @@
- /* NOT REACHED */
- }
-
--static int
-+int
- clientCachable(clientHttpRequest * http)
- {
- request_t *req = http->request;
-@@ -1637,7 +1656,7 @@
- }
-
- /* Return true if we can query our neighbors for this object */
--static int
-+int
- clientHierarchical(clientHttpRequest * http)
- {
- const char *url = http->uri;
-@@ -3351,7 +3370,7 @@
- return LOG_TCP_HIT;
- }
-
--static void
-+void
- clientProcessRequest(clientHttpRequest * http)
- {
- char *url = http->uri;
-@@ -3362,6 +3381,11 @@
- RequestMethodStr[r->method],
- url);
- r->flags.collapsed = 0;
-+#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
-@@ -3828,6 +3852,20 @@
- (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) {
-@@ -3931,7 +3969,15 @@
- /* 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
-+ * cbdataUnlock if the timeout never happens. Maybe its safe
-+ * enough to assume that if the FD is open, and the timeout
-+ * triggers, that 'http' is valid.
-+ */
- commSetTimeout(fd, Config.Timeout.lifetime, clientLifetimeTimeout, http);
- if (parser_return_code < 0) {
- debug(33, 1) ("clientReadRequest: FD %d (%s:%d) Invalid Request\n", fd, fd_table[fd].ipaddr, fd_table[fd].remote_port);
-@@ -4102,7 +4148,7 @@
- }
-
- /* 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;
-@@ -4231,7 +4277,7 @@
- }
-
- /* Abort a body request */
--static void
-+void
- clientAbortBody(request_t * request)
- {
- ConnStateData *conn = request->body_reader_data;
-@@ -4273,7 +4319,7 @@
- * 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
- */
-@@ -5015,6 +5061,52 @@
- }
- }
-
-+#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, http->orig_request);
-+ 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: squid/src/comm.c
-diff -u squid/src/comm.c:1.49 squid/src/comm.c:1.29.10.9
---- squid/src/comm.c:1.49 Mon Oct 23 04:52:53 2006
-+++ squid/src/comm.c Fri Nov 3 10:47:12 2006
-@@ -742,8 +742,8 @@
- 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: squid/src/enums.h
-diff -u squid/src/enums.h:1.57 squid/src/enums.h:1.45.4.6
---- squid/src/enums.h:1.57 Sat Sep 30 14:52:28 2006
-+++ squid/src/enums.h Fri Nov 3 10:47:13 2006
-@@ -93,6 +93,7 @@
- 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 @@
- PROTO_WHOIS,
- PROTO_INTERNAL,
- PROTO_HTTPS,
-+#if HS_FEAT_ICAP
-+ PROTO_ICAP,
-+#endif
- PROTO_MAX
- } protocol_t;
-
-@@ -630,6 +634,12 @@
- #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;
-
-@@ -730,9 +740,14 @@
- 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)
- */
-@@ -781,4 +796,68 @@
- 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: squid/src/forward.c
-diff -u squid/src/forward.c:1.42 squid/src/forward.c:1.20.4.9
---- squid/src/forward.c:1.42 Sat Sep 30 14:52:28 2006
-+++ squid/src/forward.c Fri Nov 3 10:47:13 2006
-@@ -358,8 +358,9 @@
- } 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) ||
-@@ -935,6 +936,8 @@
- 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),
-@@ -973,6 +976,8 @@
- 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);
-@@ -992,7 +997,10 @@
- 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: squid/src/globals.h
-diff -u squid/src/globals.h:1.27 squid/src/globals.h:1.22.4.5
---- squid/src/globals.h:1.27 Mon Sep 25 12:51:46 2006
-+++ squid/src/globals.h Tue Sep 26 15:47:36 2006
-@@ -171,6 +171,9 @@
- #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: squid/src/http.c
-diff -u squid/src/http.c:1.49 squid/src/http.c:1.28.4.11
---- squid/src/http.c:1.49 Mon Oct 23 14:53:15 2006
-+++ squid/src/http.c Fri Nov 3 10:47:13 2006
-@@ -47,7 +47,7 @@
-
- static PF httpReadReply;
- static void httpSendRequest(HttpStateData *);
--static PF httpStateFree;
-+PF httpStateFree;
- static PF httpTimeout;
- static void httpCacheNegatively(StoreEntry *);
- static void httpMakePrivate(StoreEntry *);
-@@ -56,12 +56,13 @@
- 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
-- delayClearNoDelay(fd);
-+ if (fd >= 0)
-+ delayClearNoDelay(fd);
- #endif
- if (httpState == NULL)
- return;
-@@ -80,6 +81,9 @@
- 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 @@
- }
-
- /* rewrite this later using new interfaces @?@ */
--static void
-+void
- httpProcessReplyHeader(HttpStateData * httpState, const char *buf, int size)
- {
- StoreEntry *entry = httpState->entry;
-@@ -552,24 +556,35 @@
- 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;
-@@ -636,6 +651,17 @@
- 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;
-@@ -647,7 +673,35 @@
- 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);
-@@ -664,7 +718,13 @@
- 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--);
-@@ -694,6 +754,12 @@
- } 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
-@@ -746,7 +812,28 @@
- EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
- }
- }
-- storeAppend(entry, buf, len);
-+#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,
-@@ -793,10 +880,21 @@
- ("httpReadReply: Excess data from \"%s %s\"\n",
- RequestMethodStr[orig_request->method],
- storeUrl(entry));
-- storeAppend(entry, buf, len);
-+#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
-@@ -852,6 +950,10 @@
- ("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;
-@@ -862,6 +964,34 @@
- }
- }
-
-+#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
-@@ -889,6 +1019,63 @@
- 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, httpState->fwd->request);
-+ 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
-@@ -897,8 +1084,18 @@
- * 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;
- }
-@@ -1192,8 +1389,11 @@
- 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))
-@@ -1319,6 +1519,7 @@
- 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],
-@@ -1361,12 +1562,22 @@
- 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: squid/src/icap_common.c
-diff -u /dev/null squid/src/icap_common.c:1.1.14.3
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/src/icap_common.c Fri May 26 12:24:02 2006
-@@ -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: squid/src/icap_opt.c
-diff -u /dev/null squid/src/icap_opt.c:1.1.16.1
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/src/icap_opt.c Wed May 17 10:58:01 2006
-@@ -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: \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: squid/src/icap_reqmod.c
-diff -u /dev/null squid/src/icap_reqmod.c:1.1.14.8
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/src/icap_reqmod.c Mon Nov 27 13:45:59 2006
-@@ -0,0 +1,988 @@
-+
-+/*
-+ * $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;
-+StoreEntry *clientCreateStoreEntry(clientHttpRequest *, method_t, request_flags);
-+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, 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, 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, icap->request);
-+ err->xerrno = xerrno;
-+ 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->chunk_size < 0 )
-+ 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) {
-+ 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: squid/src/icap_respmod.c
-diff -u /dev/null squid/src/icap_respmod.c:1.1.14.7
---- /dev/null Thu Jan 1 01:00:00 1970
-+++ squid/src/icap_respmod.c Tue Sep 26 15:47:36 2006
-@@ -0,0 +1,1058 @@
-+
-+/*
-+ * $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, 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, 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, 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, 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, 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) {
-+ if (cbdataValid(icap))
-+ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR, icap->request);
-+ else
-+ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR, NULL);
-+ err->xerrno = errno;
-+ 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, icap->request);
-+ err->xerrno = errno;
-+ 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, (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, (request_t *)request);
-+ err->xerrno = errno;
-+ 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: squid/src/main.c
-diff -u squid/src/main.c:1.72 squid/src/main.c:1.45.4.10
---- squid/src/main.c:1.72 Mon Oct 23 04:52:55 2006
-+++ squid/src/main.c Fri Nov 3 10:47:14 2006
-@@ -391,6 +391,9 @@
- #else
- idnsShutdown();
- #endif
-+#ifdef HS_FEAT_ICAP
-+ icapClose();
-+#endif
- redirectShutdown();
- locationRewriteShutdown();
- authenticateShutdown();
-@@ -422,6 +425,9 @@
- #endif
- redirectInit();
- locationRewriteInit();
-+#ifdef HS_FEAT_ICAP
-+ icapInit();
-+#endif
- authenticateInit(&Config.authConfig);
- externalAclInit();
- #if USE_WCCP
-@@ -573,6 +579,9 @@
- redirectInit();
- locationRewriteInit();
- errorMapInit();
-+#ifdef HS_FEAT_ICAP
-+ icapInit();
-+#endif
- authenticateInit(&Config.authConfig);
- externalAclInit();
- useragentOpenLog();
-Index: squid/src/mem.c
-diff -u squid/src/mem.c:1.27 squid/src/mem.c:1.24.4.3
---- squid/src/mem.c:1.27 Sat May 20 15:50:55 2006
-+++ squid/src/mem.c Fri May 26 11:21:32 2006
-@@ -353,6 +353,13 @@
- 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: squid/src/mk-string-arrays.pl
-diff -u squid/src/mk-string-arrays.pl:1.2 squid/src/mk-string-arrays.pl:1.2.180.1
---- squid/src/mk-string-arrays.pl:1.2 Mon Oct 23 08:04:21 2000
-+++ squid/src/mk-string-arrays.pl Wed May 17 10:58:01 2006
-@@ -16,6 +16,7 @@
- $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: squid/src/pconn.c
-diff -u squid/src/pconn.c:1.10 squid/src/pconn.c:1.9.4.2
---- squid/src/pconn.c:1.10 Mon May 22 15:06:12 2006
-+++ squid/src/pconn.c Fri May 26 11:21:32 2006
-@@ -46,6 +46,9 @@
- #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 @@
- 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 @@
- 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 @@
- {
- 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: squid/src/protos.h
-diff -u squid/src/protos.h:1.129 squid/src/protos.h:1.74.4.11
---- squid/src/protos.h:1.129 Mon Oct 23 04:52:55 2006
-+++ squid/src/protos.h Fri Nov 3 10:47:14 2006
-@@ -302,6 +302,8 @@
- /* 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,
-@@ -624,6 +626,7 @@
- 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);
-@@ -1417,4 +1420,53 @@
- 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: squid/src/squid.h
-diff -u squid/src/squid.h:1.36 squid/src/squid.h:1.24.8.7
---- squid/src/squid.h:1.36 Fri Sep 8 12:50:59 2006
-+++ squid/src/squid.h Tue Sep 26 15:47:38 2006
-@@ -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: squid/src/stat.c
-diff -u squid/src/stat.c:1.38 squid/src/stat.c:1.26.8.10
---- squid/src/stat.c:1.38 Wed Nov 1 13:51:29 2006
-+++ squid/src/stat.c Fri Nov 3 10:47:14 2006
-@@ -804,6 +804,17 @@
- 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",
-@@ -1188,6 +1199,17 @@
- 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",
-@@ -1488,8 +1510,6 @@
- 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: squid/src/store.c
-diff -u squid/src/store.c:1.38 squid/src/store.c:1.21.10.9
---- squid/src/store.c:1.38 Mon Oct 9 06:52:39 2006
-+++ squid/src/store.c Fri Nov 3 10:47:14 2006
-@@ -1105,8 +1105,17 @@
- 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: squid/src/structs.h
-diff -u squid/src/structs.h:1.134 squid/src/structs.h:1.81.4.11
---- squid/src/structs.h:1.134 Mon Oct 23 04:52:56 2006
-+++ squid/src/structs.h Fri Nov 3 10:47:14 2006
-@@ -423,6 +423,23 @@
- 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;
-@@ -810,6 +827,9 @@
- #endif
- time_t refresh_stale_window;
- int umask;
-+#ifdef HS_FEAT_ICAP
-+ IcapConfig icapcfg;
-+#endif
- };
-
- struct _SquidConfig2 {
-@@ -891,6 +911,10 @@
- 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;
-@@ -1095,6 +1119,131 @@
- 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;
-@@ -1106,10 +1255,14 @@
- 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;
-@@ -1218,6 +1371,7 @@
- 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 {
-@@ -1226,6 +1380,9 @@
- } redirect;
- dlink_node active;
- squid_off_t maxBodySize;
-+#if HS_FEAT_ICAP
-+ IcapStateData *icap_reqmod;
-+#endif
- };
-
- struct _ConnStateData {
-@@ -1894,6 +2051,9 @@
- 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 */
-@@ -2001,7 +2161,11 @@
- 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: squid/src/typedefs.h
-diff -u squid/src/typedefs.h:1.41 squid/src/typedefs.h:1.32.4.8
---- squid/src/typedefs.h:1.41 Sat Sep 2 07:17:45 2006
-+++ squid/src/typedefs.h Tue Sep 26 15:47:39 2006
-@@ -136,6 +136,15 @@
- 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: squid/src/url.c
-diff -u squid/src/url.c:1.17 squid/src/url.c:1.14.10.4
---- squid/src/url.c:1.17 Sat Jun 17 16:51:19 2006
-+++ squid/src/url.c Wed Jun 28 14:12:01 2006
-@@ -103,6 +103,9 @@
- "whois",
- "internal",
- "https",
-+#ifdef HS_FEAT_ICAP
-+ "icap",
-+#endif
- "TOTAL"
- };
-
-@@ -217,6 +220,10 @@
- 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 @@
- return CACHE_HTTP_PORT;
- case PROTO_WHOIS:
- return 43;
-+#ifdef HS_FEAT_ICAP
-+ case PROTO_ICAP:
-+ return 1344;
-+#endif
- default:
- return 0;
- }
diff -ruN squid-2.6.STABLE5/.metadata/.log squid-icap-2.6.STABLE5/.metadata/.log
--- squid-2.6.STABLE5/.metadata/.log 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.log 2006-12-10 16:14:36.000000000 +0200
@@ -0,0 +1,56 @@
+!SESSION 2006-12-10 16:09:49.33 ------------------------------------------------
+eclipse.buildId=M20050929-0840
+java.version=1.5.0_06
+java.vendor=Sun Microsystems Inc.
+BootLoader constants: OS=linux, ARCH=x86, WS=gtk, NL=en_US
+Command-line arguments: -os linux -ws gtk -arch x86
+
+!ENTRY org.eclipse.ui 1 0 2006-12-10 16:10:14.151
+!MESSAGE Warnings while parsing the commands from the 'org.eclipse.ui.commands' and 'org.eclipse.ui.actionDefinitions' extension points.
+!SUBENTRY 1 org.eclipse.ui 1 0 2006-12-10 16:10:14.153
+!MESSAGE Commands should really have a category, not categoryId='': plug-in='org.epic.perleditor', commandId='org.epic.perleditor.uncomment'.
+!SUBENTRY 1 org.eclipse.ui 1 0 2006-12-10 16:10:14.154
+!MESSAGE Commands should really have a category, not categoryId='': plug-in='org.epic.perleditor', commandId='org.epic.perleditor.comment'.
+!SUBENTRY 1 org.eclipse.ui 1 0 2006-12-10 16:10:14.154
+!MESSAGE Commands should really have a category, not categoryId='': plug-in='org.epic.perleditor', commandId='org.epic.perleditor.contentassist'.
+!SUBENTRY 1 org.eclipse.ui 1 0 2006-12-10 16:10:14.155
+!MESSAGE Commands should really have a category, not categoryId='': plug-in='org.epic.perleditor', commandId='org.epic.perleditor.htmlexport'.
+!SUBENTRY 1 org.eclipse.ui 1 0 2006-12-10 16:10:14.155
+!MESSAGE Commands should really have a category, not categoryId='': plug-in='org.epic.perleditor', commandId='org.epic.perleditor.formatsource'.
+
+!ENTRY org.eclipse.ui 2 0 2006-12-10 16:10:14.228
+!MESSAGE Warnings while parsing the key bindings from the 'org.eclipse.ui.commands' extension point
+!SUBENTRY 1 org.eclipse.ui 2 0 2006-12-10 16:10:14.229
+!MESSAGE Cannot bind to an undefined command: plug-in='org.epic.perleditor', commandId='org.epic.eclipse.perleditor.uncomment'.
+!SUBENTRY 1 org.eclipse.ui 2 0 2006-12-10 16:10:14.229
+!MESSAGE Cannot bind to an undefined command: plug-in='org.epic.perleditor', commandId='org.epic.eclipse.perleditor.comment'.
+
+!ENTRY org.eclipse.ui 4 4 2006-12-10 16:14:36.664
+!MESSAGE Unhandled event loop exception
+
+!ENTRY org.eclipse.ui 4 0 2006-12-10 16:14:36.692
+!MESSAGE Failed to execute runnable (java.lang.OutOfMemoryError: Java heap space)
+!STACK 0
+org.eclipse.swt.SWTException: Failed to execute runnable (java.lang.OutOfMemoryError: Java heap space)
+ at org.eclipse.swt.SWT.error(SWT.java:2942)
+ at org.eclipse.swt.SWT.error(SWT.java:2865)
+ at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:126)
+ at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:2844)
+ at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:2575)
+ at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:1699)
+ at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:1663)
+ at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:367)
+ at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:143)
+ at org.eclipse.ui.internal.ide.IDEApplication.run(IDEApplication.java:103)
+ at org.eclipse.core.internal.runtime.PlatformActivator$1.run(PlatformActivator.java:226)
+ at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:376)
+ at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:163)
+ at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+ at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
+ at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
+ at java.lang.reflect.Method.invoke(Unknown Source)
+ at org.eclipse.core.launcher.Main.invokeFramework(Main.java:334)
+ at org.eclipse.core.launcher.Main.basicRun(Main.java:278)
+ at org.eclipse.core.launcher.Main.run(Main.java:973)
+ at org.eclipse.core.launcher.Main.main(Main.java:948)
+Caused by: java.lang.OutOfMemoryError: Java heap space
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.cdt.make.core/specs.c squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.cdt.make.core/specs.c
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.cdt.make.core/specs.c 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.cdt.make.core/specs.c 2006-12-10 16:10:49.000000000 +0200
@@ -0,0 +1 @@
+
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.cdt.make.core/specs.cpp squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.cdt.make.core/specs.cpp
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.cdt.make.core/specs.cpp 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.cdt.make.core/specs.cpp 2006-12-10 16:10:49.000000000 +0200
@@ -0,0 +1 @@
+
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/0/c0b716325c88001b16add8656805b17d squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/0/c0b716325c88001b16add8656805b17d
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/0/c0b716325c88001b16add8656805b17d 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/0/c0b716325c88001b16add8656805b17d 2006-12-10 16:10:54.000000000 +0200
@@ -0,0 +1,43 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+ROOT := ..
+
+-include $(ROOT)/makefile.init
+
+RM := rm -rf
+
+# All of the sources participating in the build are defined here
+-include sources.mk
+-include $(SUBDIRS:%=%/subdir.mk)
+-include objects.mk
+ifneq ($(strip $(DEPS)),)
+-include $(DEPS)
+endif
+
+-include $(ROOT)/makefile.defs
+
+# Add inputs and outputs from these tool invocations to the build variables
+
+# All Target
+all: src
+
+# Tool invocations
+src: $(OBJS) $(USER_OBJS)
+ @echo 'Building target: $@'
+ @echo 'Invoking: GCC C Linker'
+ @echo gcc -osrc $(OBJS) $(USER_OBJS) $(LIBS)
+ @gcc -osrc $(OBJS) $(USER_OBJS) $(LIBS)
+ @echo 'Finished building target: $@'
+ @echo ' '
+
+# Other Targets
+clean:
+ -$(RM) $(OBJS)$(DEPS)$(EXECUTABLES) src
+ -@echo ' '
+
+.PHONY: all clean dependents
+.SECONDARY:
+
+-include $(ROOT)/makefile.targets
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/16/0065afda5f88001b16add8656805b17d squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/16/0065afda5f88001b16add8656805b17d
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/16/0065afda5f88001b16add8656805b17d 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/16/0065afda5f88001b16add8656805b17d 2006-12-10 16:09:19.000000000 +0200
@@ -0,0 +1,1058 @@
+
+/*
+ * $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, 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, 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, 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, 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, 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) {
+ if (cbdataValid(icap))
+ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR, icap->request);
+ else
+ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR, NULL);
+ err->xerrno = errno;
+ 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, icap->request);
+ err->xerrno = errno;
+ 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, (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, (request_t *)request);
+ err->xerrno = errno;
+ 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");
+ }
+}
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/28/105700105f88001b16add8656805b17d squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/28/105700105f88001b16add8656805b17d
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/28/105700105f88001b16add8656805b17d 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/28/105700105f88001b16add8656805b17d 2006-12-10 16:09:19.000000000 +0200
@@ -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));
+}
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/2f/603c963c5888001b16add8656805b17d squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/2f/603c963c5888001b16add8656805b17d
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/2f/603c963c5888001b16add8656805b17d 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/2f/603c963c5888001b16add8656805b17d 2006-12-10 16:10:49.000000000 +0200
@@ -0,0 +1,12 @@
+
+
+ src
+
+
+
+
+
+
+ org.eclipse.cdt.core.cnature
+
+
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/38/00d19a315c88001b16add8656805b17d squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/38/00d19a315c88001b16add8656805b17d
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/38/00d19a315c88001b16add8656805b17d 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/38/00d19a315c88001b16add8656805b17d 2006-12-10 16:10:54.000000000 +0200
@@ -0,0 +1,365 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+# Add inputs and outputs from these tool invocations to the build variables
+C_SRCS += \
+$(ROOT)/CacheDigest.c \
+$(ROOT)/HttpBody.c \
+$(ROOT)/HttpHdrCc.c \
+$(ROOT)/HttpHdrContRange.c \
+$(ROOT)/HttpHdrRange.c \
+$(ROOT)/HttpHeader.c \
+$(ROOT)/HttpHeaderTools.c \
+$(ROOT)/HttpMsg.c \
+$(ROOT)/HttpReply.c \
+$(ROOT)/HttpRequest.c \
+$(ROOT)/HttpStatusLine.c \
+$(ROOT)/MemBuf.c \
+$(ROOT)/MemPool.c \
+$(ROOT)/Packer.c \
+$(ROOT)/StatHist.c \
+$(ROOT)/String.c \
+$(ROOT)/access_log.c \
+$(ROOT)/acl.c \
+$(ROOT)/asn.c \
+$(ROOT)/authenticate.c \
+$(ROOT)/cache_cf.c \
+$(ROOT)/cache_manager.c \
+$(ROOT)/carp.c \
+$(ROOT)/cbdata.c \
+$(ROOT)/cf_gen.c \
+$(ROOT)/client_db.c \
+$(ROOT)/client_side.c \
+$(ROOT)/comm.c \
+$(ROOT)/comm_epoll.c \
+$(ROOT)/comm_generic.c \
+$(ROOT)/comm_kqueue.c \
+$(ROOT)/comm_poll.c \
+$(ROOT)/comm_select.c \
+$(ROOT)/comm_select_simple.c \
+$(ROOT)/comm_select_win32.c \
+$(ROOT)/debug.c \
+$(ROOT)/delay_pools.c \
+$(ROOT)/disk.c \
+$(ROOT)/dns.c \
+$(ROOT)/dns_internal.c \
+$(ROOT)/dnsserver.c \
+$(ROOT)/errormap.c \
+$(ROOT)/errorpage.c \
+$(ROOT)/event.c \
+$(ROOT)/external_acl.c \
+$(ROOT)/fd.c \
+$(ROOT)/filemap.c \
+$(ROOT)/forward.c \
+$(ROOT)/fqdncache.c \
+$(ROOT)/ftp.c \
+$(ROOT)/gopher.c \
+$(ROOT)/helper.c \
+$(ROOT)/htcp.c \
+$(ROOT)/http.c \
+$(ROOT)/icap_common.c \
+$(ROOT)/icap_opt.c \
+$(ROOT)/icap_reqmod.c \
+$(ROOT)/icap_respmod.c \
+$(ROOT)/icmp.c \
+$(ROOT)/icp_v2.c \
+$(ROOT)/icp_v3.c \
+$(ROOT)/ident.c \
+$(ROOT)/internal.c \
+$(ROOT)/ipc.c \
+$(ROOT)/ipc_win32.c \
+$(ROOT)/ipcache.c \
+$(ROOT)/leakfinder.c \
+$(ROOT)/locrewrite.c \
+$(ROOT)/logfile.c \
+$(ROOT)/main.c \
+$(ROOT)/mem.c \
+$(ROOT)/mime.c \
+$(ROOT)/multicast.c \
+$(ROOT)/neighbors.c \
+$(ROOT)/net_db.c \
+$(ROOT)/pconn.c \
+$(ROOT)/peer_digest.c \
+$(ROOT)/peer_monitor.c \
+$(ROOT)/peer_select.c \
+$(ROOT)/peer_sourcehash.c \
+$(ROOT)/peer_userhash.c \
+$(ROOT)/pinger.c \
+$(ROOT)/redirect.c \
+$(ROOT)/referer.c \
+$(ROOT)/refresh.c \
+$(ROOT)/send-announce.c \
+$(ROOT)/snmp_agent.c \
+$(ROOT)/snmp_core.c \
+$(ROOT)/ssl.c \
+$(ROOT)/ssl_support.c \
+$(ROOT)/stat.c \
+$(ROOT)/stmem.c \
+$(ROOT)/store.c \
+$(ROOT)/store_client.c \
+$(ROOT)/store_digest.c \
+$(ROOT)/store_dir.c \
+$(ROOT)/store_io.c \
+$(ROOT)/store_key_md5.c \
+$(ROOT)/store_log.c \
+$(ROOT)/store_rebuild.c \
+$(ROOT)/store_swapin.c \
+$(ROOT)/store_swapmeta.c \
+$(ROOT)/store_swapout.c \
+$(ROOT)/tools.c \
+$(ROOT)/unlinkd.c \
+$(ROOT)/url.c \
+$(ROOT)/urn.c \
+$(ROOT)/useragent.c \
+$(ROOT)/wais.c \
+$(ROOT)/wccp.c \
+$(ROOT)/wccp2.c \
+$(ROOT)/whois.c \
+$(ROOT)/win32.c
+
+OBJS += \
+./CacheDigest.o \
+./HttpBody.o \
+./HttpHdrCc.o \
+./HttpHdrContRange.o \
+./HttpHdrRange.o \
+./HttpHeader.o \
+./HttpHeaderTools.o \
+./HttpMsg.o \
+./HttpReply.o \
+./HttpRequest.o \
+./HttpStatusLine.o \
+./MemBuf.o \
+./MemPool.o \
+./Packer.o \
+./StatHist.o \
+./String.o \
+./access_log.o \
+./acl.o \
+./asn.o \
+./authenticate.o \
+./cache_cf.o \
+./cache_manager.o \
+./carp.o \
+./cbdata.o \
+./cf_gen.o \
+./client_db.o \
+./client_side.o \
+./comm.o \
+./comm_epoll.o \
+./comm_generic.o \
+./comm_kqueue.o \
+./comm_poll.o \
+./comm_select.o \
+./comm_select_simple.o \
+./comm_select_win32.o \
+./debug.o \
+./delay_pools.o \
+./disk.o \
+./dns.o \
+./dns_internal.o \
+./dnsserver.o \
+./errormap.o \
+./errorpage.o \
+./event.o \
+./external_acl.o \
+./fd.o \
+./filemap.o \
+./forward.o \
+./fqdncache.o \
+./ftp.o \
+./gopher.o \
+./helper.o \
+./htcp.o \
+./http.o \
+./icap_common.o \
+./icap_opt.o \
+./icap_reqmod.o \
+./icap_respmod.o \
+./icmp.o \
+./icp_v2.o \
+./icp_v3.o \
+./ident.o \
+./internal.o \
+./ipc.o \
+./ipc_win32.o \
+./ipcache.o \
+./leakfinder.o \
+./locrewrite.o \
+./logfile.o \
+./main.o \
+./mem.o \
+./mime.o \
+./multicast.o \
+./neighbors.o \
+./net_db.o \
+./pconn.o \
+./peer_digest.o \
+./peer_monitor.o \
+./peer_select.o \
+./peer_sourcehash.o \
+./peer_userhash.o \
+./pinger.o \
+./redirect.o \
+./referer.o \
+./refresh.o \
+./send-announce.o \
+./snmp_agent.o \
+./snmp_core.o \
+./ssl.o \
+./ssl_support.o \
+./stat.o \
+./stmem.o \
+./store.o \
+./store_client.o \
+./store_digest.o \
+./store_dir.o \
+./store_io.o \
+./store_key_md5.o \
+./store_log.o \
+./store_rebuild.o \
+./store_swapin.o \
+./store_swapmeta.o \
+./store_swapout.o \
+./tools.o \
+./unlinkd.o \
+./url.o \
+./urn.o \
+./useragent.o \
+./wais.o \
+./wccp.o \
+./wccp2.o \
+./whois.o \
+./win32.o
+
+DEPS += \
+${addprefix ./, \
+CacheDigest.d \
+HttpBody.d \
+HttpHdrCc.d \
+HttpHdrContRange.d \
+HttpHdrRange.d \
+HttpHeader.d \
+HttpHeaderTools.d \
+HttpMsg.d \
+HttpReply.d \
+HttpRequest.d \
+HttpStatusLine.d \
+MemBuf.d \
+MemPool.d \
+Packer.d \
+StatHist.d \
+String.d \
+access_log.d \
+acl.d \
+asn.d \
+authenticate.d \
+cache_cf.d \
+cache_manager.d \
+carp.d \
+cbdata.d \
+cf_gen.d \
+client_db.d \
+client_side.d \
+comm.d \
+comm_epoll.d \
+comm_generic.d \
+comm_kqueue.d \
+comm_poll.d \
+comm_select.d \
+comm_select_simple.d \
+comm_select_win32.d \
+debug.d \
+delay_pools.d \
+disk.d \
+dns.d \
+dns_internal.d \
+dnsserver.d \
+errormap.d \
+errorpage.d \
+event.d \
+external_acl.d \
+fd.d \
+filemap.d \
+forward.d \
+fqdncache.d \
+ftp.d \
+gopher.d \
+helper.d \
+htcp.d \
+http.d \
+icap_common.d \
+icap_opt.d \
+icap_reqmod.d \
+icap_respmod.d \
+icmp.d \
+icp_v2.d \
+icp_v3.d \
+ident.d \
+internal.d \
+ipc.d \
+ipc_win32.d \
+ipcache.d \
+leakfinder.d \
+locrewrite.d \
+logfile.d \
+main.d \
+mem.d \
+mime.d \
+multicast.d \
+neighbors.d \
+net_db.d \
+pconn.d \
+peer_digest.d \
+peer_monitor.d \
+peer_select.d \
+peer_sourcehash.d \
+peer_userhash.d \
+pinger.d \
+redirect.d \
+referer.d \
+refresh.d \
+send-announce.d \
+snmp_agent.d \
+snmp_core.d \
+ssl.d \
+ssl_support.d \
+stat.d \
+stmem.d \
+store.d \
+store_client.d \
+store_digest.d \
+store_dir.d \
+store_io.d \
+store_key_md5.d \
+store_log.d \
+store_rebuild.d \
+store_swapin.d \
+store_swapmeta.d \
+store_swapout.d \
+tools.d \
+unlinkd.d \
+url.d \
+urn.d \
+useragent.d \
+wais.d \
+wccp.d \
+wccp2.d \
+whois.d \
+win32.d \
+}
+
+
+# Each subdirectory must supply rules for building sources it contributes
+%.o: $(ROOT)/%.c
+ @echo 'Building file: $<'
+ @echo 'Invoking: GCC C Compiler'
+ @echo gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $<
+ @gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $< && \
+ echo -n $(@:%.o=%.d) $(dir $@) > $(@:%.o=%.d) && \
+ gcc -MM -MG -P -w -O0 -g3 -Wall -c -fmessage-length=0 $< >> $(@:%.o=%.d)
+ @echo 'Finished building: $<'
+ @echo ' '
+
+
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/3d/c0c5ea315c88001b16add8656805b17d squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/3d/c0c5ea315c88001b16add8656805b17d
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/3d/c0c5ea315c88001b16add8656805b17d 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/3d/c0c5ea315c88001b16add8656805b17d 2006-12-10 16:10:54.000000000 +0200
@@ -0,0 +1,29 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+# Add inputs and outputs from these tool invocations to the build variables
+C_SRCS += \
+$(ROOT)/auth/digest/auth_digest.c
+
+OBJS += \
+./auth/digest/auth_digest.o
+
+DEPS += \
+${addprefix ./auth/digest/, \
+auth_digest.d \
+}
+
+
+# Each subdirectory must supply rules for building sources it contributes
+auth/digest/%.o: $(ROOT)/auth/digest/%.c
+ @echo 'Building file: $<'
+ @echo 'Invoking: GCC C Compiler'
+ @echo gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $<
+ @gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $< && \
+ echo -n $(@:%.o=%.d) $(dir $@) > $(@:%.o=%.d) && \
+ gcc -MM -MG -P -w -O0 -g3 -Wall -c -fmessage-length=0 $< >> $(@:%.o=%.d)
+ @echo 'Finished building: $<'
+ @echo ' '
+
+
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/4d/5022ea3f5888001b16add8656805b17d squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/4d/5022ea3f5888001b16add8656805b17d
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/4d/5022ea3f5888001b16add8656805b17d 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/4d/5022ea3f5888001b16add8656805b17d 2006-12-10 16:10:54.000000000 +0200
@@ -0,0 +1,3 @@
+#Sun Dec 10 16:10:54 IST 2006
+eclipse.preferences.version=1
+environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.debug.1102957643=\n\n\n\n\n
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/5c/402a8c3c5888001b16add8656805b17d squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/5c/402a8c3c5888001b16add8656805b17d
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/5c/402a8c3c5888001b16add8656805b17d 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/5c/402a8c3c5888001b16add8656805b17d 2006-12-10 16:10:48.000000000 +0200
@@ -0,0 +1,11 @@
+
+
+ src
+
+
+
+
+
+
+
+
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/62/9033cd365f88001b16add8656805b17d squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/62/9033cd365f88001b16add8656805b17d
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/62/9033cd365f88001b16add8656805b17d 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/62/9033cd365f88001b16add8656805b17d 2006-12-10 16:59:40.000000000 +0200
@@ -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);
+ cap->respmod.icap_server_session_context = NULL;
+ 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));
+}
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/67/d04d973c5888001b16add8656805b17d squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/67/d04d973c5888001b16add8656805b17d
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/67/d04d973c5888001b16add8656805b17d 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/67/d04d973c5888001b16add8656805b17d 2006-12-10 16:10:49.000000000 +0200
@@ -0,0 +1,13 @@
+
+
+ src
+
+
+
+
+
+
+ org.eclipse.cdt.core.cnature
+ org.eclipse.cdt.managedbuilder.core.managedBuildNature
+
+
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/7c/b06f2d606088001b16add8656805b17d squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/7c/b06f2d606088001b16add8656805b17d
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/7c/b06f2d606088001b16add8656805b17d 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/7c/b06f2d606088001b16add8656805b17d 2006-12-10 17:05:21.000000000 +0200
@@ -0,0 +1,1066 @@
+
+/*
+ * $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 (icap->respmod.icap_server_session_context != NULL )
+ {
+ debug(81, 5)( "sending icap context to server %s: %s\r\n",
+ Config.icapcfg.icap_session_context_tag_name,
+ icap->respmod.icap_server_session_context);
+ memBufPrintf(mb, "%s: %s\r\n", Config.icapcfg.icap_session_context_tag_name,
+ icap->respmod.icap_server_session_context);
+ }
+ 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, 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, 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, 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, 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, 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) {
+ if (cbdataValid(icap))
+ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR, icap->request);
+ else
+ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR, NULL);
+ err->xerrno = errno;
+ 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, icap->request);
+ err->xerrno = errno;
+ 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, (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, (request_t *)request);
+ err->xerrno = errno;
+ 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");
+ }
+}
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/80/7079fecb6888001b16add8656805b17d squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/80/7079fecb6888001b16add8656805b17d
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/80/7079fecb6888001b16add8656805b17d 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/80/7079fecb6888001b16add8656805b17d 2006-12-10 16:09:19.000000000 +0200
@@ -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: \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);
+ }
+}
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/8d/2036ac315c88001b16add8656805b17d squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/8d/2036ac315c88001b16add8656805b17d
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/8d/2036ac315c88001b16add8656805b17d 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/8d/2036ac315c88001b16add8656805b17d 2006-12-10 16:10:54.000000000 +0200
@@ -0,0 +1,32 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+# Add inputs and outputs from these tool invocations to the build variables
+C_SRCS += \
+$(ROOT)/repl/heap/store_heap_replacement.c \
+$(ROOT)/repl/heap/store_repl_heap.c
+
+OBJS += \
+./repl/heap/store_heap_replacement.o \
+./repl/heap/store_repl_heap.o
+
+DEPS += \
+${addprefix ./repl/heap/, \
+store_heap_replacement.d \
+store_repl_heap.d \
+}
+
+
+# Each subdirectory must supply rules for building sources it contributes
+repl/heap/%.o: $(ROOT)/repl/heap/%.c
+ @echo 'Building file: $<'
+ @echo 'Invoking: GCC C Compiler'
+ @echo gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $<
+ @gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $< && \
+ echo -n $(@:%.o=%.d) $(dir $@) > $(@:%.o=%.d) && \
+ gcc -MM -MG -P -w -O0 -g3 -Wall -c -fmessage-length=0 $< >> $(@:%.o=%.d)
+ @echo 'Finished building: $<'
+ @echo ' '
+
+
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/8f/4005d6315c88001b16add8656805b17d squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/8f/4005d6315c88001b16add8656805b17d
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/8f/4005d6315c88001b16add8656805b17d 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/8f/4005d6315c88001b16add8656805b17d 2006-12-10 16:10:54.000000000 +0200
@@ -0,0 +1,41 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+# Add inputs and outputs from these tool invocations to the build variables
+C_SRCS += \
+$(ROOT)/fs/aufs/aiops.c \
+$(ROOT)/fs/aufs/aiops_win32.c \
+$(ROOT)/fs/aufs/async_io.c \
+$(ROOT)/fs/aufs/store_dir_aufs.c \
+$(ROOT)/fs/aufs/store_io_aufs.c
+
+OBJS += \
+./fs/aufs/aiops.o \
+./fs/aufs/aiops_win32.o \
+./fs/aufs/async_io.o \
+./fs/aufs/store_dir_aufs.o \
+./fs/aufs/store_io_aufs.o
+
+DEPS += \
+${addprefix ./fs/aufs/, \
+aiops.d \
+aiops_win32.d \
+async_io.d \
+store_dir_aufs.d \
+store_io_aufs.d \
+}
+
+
+# Each subdirectory must supply rules for building sources it contributes
+fs/aufs/%.o: $(ROOT)/fs/aufs/%.c
+ @echo 'Building file: $<'
+ @echo 'Invoking: GCC C Compiler'
+ @echo gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $<
+ @gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $< && \
+ echo -n $(@:%.o=%.d) $(dir $@) > $(@:%.o=%.d) && \
+ gcc -MM -MG -P -w -O0 -g3 -Wall -c -fmessage-length=0 $< >> $(@:%.o=%.d)
+ @echo 'Finished building: $<'
+ @echo ' '
+
+
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/95/4058dd315c88001b16add8656805b17d squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/95/4058dd315c88001b16add8656805b17d
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/95/4058dd315c88001b16add8656805b17d 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/95/4058dd315c88001b16add8656805b17d 2006-12-10 16:10:54.000000000 +0200
@@ -0,0 +1,29 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+# Add inputs and outputs from these tool invocations to the build variables
+C_SRCS += \
+$(ROOT)/auth/ntlm/auth_ntlm.c
+
+OBJS += \
+./auth/ntlm/auth_ntlm.o
+
+DEPS += \
+${addprefix ./auth/ntlm/, \
+auth_ntlm.d \
+}
+
+
+# Each subdirectory must supply rules for building sources it contributes
+auth/ntlm/%.o: $(ROOT)/auth/ntlm/%.c
+ @echo 'Building file: $<'
+ @echo 'Invoking: GCC C Compiler'
+ @echo gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $<
+ @gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $< && \
+ echo -n $(@:%.o=%.d) $(dir $@) > $(@:%.o=%.d) && \
+ gcc -MM -MG -P -w -O0 -g3 -Wall -c -fmessage-length=0 $< >> $(@:%.o=%.d)
+ @echo 'Finished building: $<'
+ @echo ' '
+
+
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/9b/80a8c0315c88001b16add8656805b17d squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/9b/80a8c0315c88001b16add8656805b17d
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/9b/80a8c0315c88001b16add8656805b17d 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/9b/80a8c0315c88001b16add8656805b17d 2006-12-10 16:10:54.000000000 +0200
@@ -0,0 +1,29 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+# Add inputs and outputs from these tool invocations to the build variables
+C_SRCS += \
+$(ROOT)/fs/null/store_null.c
+
+OBJS += \
+./fs/null/store_null.o
+
+DEPS += \
+${addprefix ./fs/null/, \
+store_null.d \
+}
+
+
+# Each subdirectory must supply rules for building sources it contributes
+fs/null/%.o: $(ROOT)/fs/null/%.c
+ @echo 'Building file: $<'
+ @echo 'Invoking: GCC C Compiler'
+ @echo gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $<
+ @gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $< && \
+ echo -n $(@:%.o=%.d) $(dir $@) > $(@:%.o=%.d) && \
+ gcc -MM -MG -P -w -O0 -g3 -Wall -c -fmessage-length=0 $< >> $(@:%.o=%.d)
+ @echo 'Finished building: $<'
+ @echo ' '
+
+
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/9c/40b3b6286888001b16add8656805b17d squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/9c/40b3b6286888001b16add8656805b17d
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/9c/40b3b6286888001b16add8656805b17d 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/9c/40b3b6286888001b16add8656805b17d 2006-12-10 16:09:19.000000000 +0200
@@ -0,0 +1,1169 @@
+
+/*
+ * $Id: main.c,v 1.392 2006/10/23 11:22:21 hno Exp $
+ *
+ * DEBUG: section 1 Startup and Main Loop
+ * AUTHOR: Harvest Derived
+ *
+ * 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"
+
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+#include
+#include
+static int opt_install_service = FALSE;
+static int opt_remove_service = FALSE;
+static int opt_signal_service = FALSE;
+static int opt_command_line = FALSE;
+extern void WIN32_svcstatusupdate(DWORD, DWORD);
+void WINAPI WIN32_svcHandler(DWORD);
+#endif
+
+/* for error reporting from xmalloc and friends */
+extern void (*failure_notify) (const char *);
+
+static char *opt_syslog_facility = NULL;
+static int icpPortNumOverride = 1; /* Want to detect "-u 0" */
+static int configured_once = 0;
+#if MALLOC_DBG
+static int malloc_debug_level = 0;
+#endif
+static volatile int do_reconfigure = 0;
+static volatile int do_rotate = 0;
+static volatile int do_shutdown = 0;
+
+static void mainRotate(void);
+static void mainReconfigure(void);
+static void mainInitialize(void);
+static void usage(void);
+static void mainParseOptions(int, char **);
+static void sendSignal(void);
+static void serverConnectionsOpen(void);
+static void watch_child(char **);
+static void setEffectiveUser(void);
+#if MEM_GEN_TRACE
+extern void log_trace_done();
+extern void log_trace_init(char *);
+#endif
+static EVH SquidShutdown;
+static void mainSetCwd(void);
+static int checkRunningPid(void);
+
+#ifndef _SQUID_MSWIN_
+static const char *squid_start_script = "squid_start";
+#endif
+
+#if TEST_ACCESS
+#include "test_access.c"
+#endif
+
+static void
+usage(void)
+{
+ fprintf(stderr,
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ "Usage: %s [-hirvzCDFRYX] [-d level] [-s | -l facility] [-f config-file] [-u port] [-k signal] [-n name] [-O command-line]\n"
+#else
+ "Usage: %s [-hvzCDFNRYX] [-d level] [-s | -l facility] [-f config-file] [-u port] [-k signal]\n"
+#endif
+ " -d level Write debugging to stderr also.\n"
+ " -f file Use given config-file instead of\n"
+ " %s\n"
+ " -h Print help message.\n"
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ " -i Installs as a Windows Service (see -n option).\n"
+#endif
+ " -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n"
+ " Parse configuration file, then send signal to \n"
+ " running copy (except -k parse) and exit.\n"
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ " -n name Specify Windows Service name to use for service operations\n"
+ " default is: " _WIN_SQUID_DEFAULT_SERVICE_NAME ".\n"
+ " -r Removes a Windows Service (see -n option).\n"
+#endif
+ " -s | -l facility\n"
+ " Enable logging to syslog.\n"
+ " -u port Specify ICP port number (default: %d), disable with 0.\n"
+ " -v Print version.\n"
+ " -z Create swap directories\n"
+ " -C Do not catch fatal signals.\n"
+ " -D Disable initial DNS tests.\n"
+ " -F Don't serve any requests until store is rebuilt.\n"
+ " -N No daemon mode.\n"
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ " -O options\n"
+ " Set Windows Service Command line options in Registry.\n"
+#endif
+ " -R Do not set REUSEADDR on port.\n"
+ " -S Double-check swap during rebuild.\n"
+ " -X Force full debugging.\n"
+ " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
+ appname, DefaultConfigFile, CACHE_ICP_PORT);
+ exit(1);
+}
+
+static void
+mainParseOptions(int argc, char *argv[])
+{
+ extern char *optarg;
+ int c;
+
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ while ((c = getopt(argc, argv, "CDFO:RSYXd:f:hik:m::n:rsl:u:vz?")) != -1) {
+#else
+ while ((c = getopt(argc, argv, "CDFNRSYXd:f:hk:m::sl:u:vz?")) != -1) {
+#endif
+ switch (c) {
+ case 'C':
+ opt_catch_signals = 0;
+ break;
+ case 'D':
+ opt_dns_tests = 0;
+ break;
+ case 'F':
+ opt_foreground_rebuild = 1;
+ break;
+ case 'N':
+ opt_no_daemon = 1;
+ break;
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ case 'O':
+ opt_command_line = 1;
+ WIN32_Command_Line = xstrdup(optarg);
+ break;
+#endif
+ case 'R':
+ opt_reuseaddr = 0;
+ break;
+ case 'S':
+ opt_store_doublecheck = 1;
+ break;
+ case 'X':
+ /* force full debugging */
+ sigusr2_handle(SIGUSR2);
+ break;
+ case 'Y':
+ opt_reload_hit_only = 1;
+ break;
+ case 'd':
+ opt_debug_stderr = atoi(optarg);
+ break;
+ case 'f':
+ xfree(ConfigFile);
+ ConfigFile = xstrdup(optarg);
+ break;
+ case 'h':
+ usage();
+ break;
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ case 'i':
+ opt_install_service = TRUE;
+ break;
+#endif
+ case 'k':
+ if ((int) strlen(optarg) < 1)
+ usage();
+ if (!strncmp(optarg, "reconfigure", strlen(optarg)))
+ opt_send_signal = SIGHUP;
+ else if (!strncmp(optarg, "rotate", strlen(optarg)))
+#ifdef _SQUID_LINUX_THREADS_
+ opt_send_signal = SIGQUIT;
+#else
+ opt_send_signal = SIGUSR1;
+#endif
+ else if (!strncmp(optarg, "debug", strlen(optarg)))
+#ifdef _SQUID_LINUX_THREADS_
+ opt_send_signal = SIGTRAP;
+#else
+ opt_send_signal = SIGUSR2;
+#endif
+ else if (!strncmp(optarg, "shutdown", strlen(optarg)))
+ opt_send_signal = SIGTERM;
+ else if (!strncmp(optarg, "interrupt", strlen(optarg)))
+ opt_send_signal = SIGINT;
+ else if (!strncmp(optarg, "kill", strlen(optarg)))
+ opt_send_signal = SIGKILL;
+ else if (!strncmp(optarg, "check", strlen(optarg)))
+ opt_send_signal = 0; /* SIGNULL */
+ else if (!strncmp(optarg, "parse", strlen(optarg)))
+ opt_parse_cfg_only = 1; /* parse cfg file only */
+ else
+ usage();
+ break;
+ case 'm':
+ if (optarg) {
+#if MALLOC_DBG
+ malloc_debug_level = atoi(optarg);
+ /* NOTREACHED */
+ break;
+#else
+ fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
+ /* NOTREACHED */
+#endif
+ } else {
+#if XMALLOC_TRACE
+ xmalloc_trace = !xmalloc_trace;
+#else
+ fatal("Need to configure --enable-xmalloc-debug-trace to use -m option");
+#endif
+ }
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ case 'n':
+ xfree(WIN32_Service_name);
+ WIN32_Service_name = xstrdup(optarg);
+ opt_signal_service = TRUE;
+ break;
+ case 'r':
+ opt_remove_service = TRUE;
+ break;
+#endif
+ case 'l':
+ opt_syslog_facility = xstrdup(optarg);
+ case 's':
+#if HAVE_SYSLOG
+ _db_set_syslog(opt_syslog_facility);
+ break;
+#else
+ fatal("Logging to syslog not available on this platform");
+ /* NOTREACHED */
+#endif
+ case 'u':
+ icpPortNumOverride = atoi(optarg);
+ if (icpPortNumOverride < 0)
+ icpPortNumOverride = 0;
+ break;
+ case 'v':
+ printf("Squid Cache: Version %s\nconfigure options: %s\n", version_string, SQUID_CONFIGURE_OPTIONS);
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ printf("Compiled as Windows System Service.\n");
+#endif
+ exit(0);
+ /* NOTREACHED */
+ case 'z':
+ opt_create_swap_dirs = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ break;
+ }
+ }
+}
+
+/* ARGSUSED */
+void
+rotate_logs(int sig)
+{
+ do_rotate = 1;
+#ifndef _SQUID_MSWIN_
+#if !HAVE_SIGACTION
+ signal(sig, rotate_logs);
+#endif
+#endif
+}
+
+/* ARGSUSED */
+void
+reconfigure(int sig)
+{
+ do_reconfigure = 1;
+#ifndef _SQUID_MSWIN_
+#if !HAVE_SIGACTION
+ signal(sig, reconfigure);
+#endif
+#endif
+}
+
+void
+shut_down(int sig)
+{
+ do_shutdown = sig == SIGINT ? -1 : 1;
+#ifndef _SQUID_MSWIN_
+#ifdef KILL_PARENT_OPT
+ if (getppid() > 1) {
+ debug(1, 1) ("Killing RunCache, pid %ld\n", (long) getppid());
+ if (kill(getppid(), sig) < 0)
+ debug(1, 1) ("kill %ld: %s\n", (long) getppid(), xstrerror());
+ }
+#endif
+#if SA_RESETHAND == 0
+ signal(SIGTERM, SIG_DFL);
+ signal(SIGINT, SIG_DFL);
+#endif
+#endif
+}
+
+static void
+serverConnectionsOpen(void)
+{
+ clientOpenListenSockets();
+ icpConnectionsOpen();
+#if USE_HTCP
+ htcpInit();
+#endif
+#ifdef SQUID_SNMP
+ snmpConnectionOpen();
+#endif
+#if USE_WCCP
+ wccpConnectionOpen();
+#endif
+#if USE_WCCPv2
+ wccp2ConnectionOpen();
+#endif
+ clientdbInit();
+ icmpOpen();
+ netdbInit();
+ asnInit();
+ peerSelectInit();
+#if USE_CARP
+ carpInit();
+#endif
+ peerSourceHashInit();
+ peerUserHashInit();
+ peerMonitorInit();
+}
+
+void
+serverConnectionsClose(void)
+{
+ assert(shutting_down || reconfiguring);
+ clientHttpConnectionsClose();
+ icpConnectionShutdown();
+#if USE_HTCP
+ htcpSocketShutdown();
+#endif
+ icmpClose();
+#ifdef SQUID_SNMP
+ snmpConnectionShutdown();
+#endif
+#if USE_WCCP
+ wccpConnectionClose();
+#endif
+#if USE_WCCPv2
+ wccp2ConnectionClose();
+#endif
+ asnFreeMemory();
+}
+
+static void
+mainReconfigure(void)
+{
+ debug(1, 1) ("Reconfiguring Squid Cache (version %s)...\n", version_string);
+ reconfiguring = 1;
+ /* Already called serverConnectionsClose and ipcacheShutdownServers() */
+ serverConnectionsClose();
+ icpConnectionClose();
+#if USE_HTCP
+ htcpSocketClose();
+#endif
+#ifdef SQUID_SNMP
+ snmpConnectionClose();
+#endif
+#if USE_DNSSERVERS
+ dnsShutdown();
+#else
+ idnsShutdown();
+#endif
+#ifdef HS_FEAT_ICAP
+ icapClose();
+#endif
+ redirectShutdown();
+ locationRewriteShutdown();
+ authenticateShutdown();
+ externalAclShutdown();
+ storeDirCloseSwapLogs();
+ storeLogClose();
+ accessLogClose();
+ useragentLogClose();
+ refererCloseLog();
+ errorClean();
+ enter_suid(); /* root to read config file */
+ parseConfigFile(ConfigFile);
+ setUmask(Config.umask);
+ setEffectiveUser();
+ _db_init(Config.Log.log, Config.debugOptions);
+ ipcache_restart(); /* clear stuck entries */
+ authenticateUserCacheRestart(); /* clear stuck ACL entries */
+ fqdncache_restart(); /* sigh, fqdncache too */
+ parseEtcHosts();
+ errorInitialize(); /* reload error pages */
+ accessLogInit();
+ storeLogOpen();
+ useragentOpenLog();
+ refererOpenLog();
+#if USE_DNSSERVERS
+ dnsInit();
+#else
+ idnsInit();
+#endif
+ redirectInit();
+ locationRewriteInit();
+#ifdef HS_FEAT_ICAP
+ icapInit();
+#endif
+ authenticateInit(&Config.authConfig);
+ externalAclInit();
+#if USE_WCCP
+ wccpInit();
+#endif
+#if USE_WCCPv2
+ wccp2Init();
+#endif
+ serverConnectionsOpen();
+ neighbors_init();
+ storeDirOpenSwapLogs();
+ mimeInit(Config.mimeTablePathname);
+ if (Config.onoff.announce) {
+ if (!eventFind(start_announce, NULL))
+ eventAdd("start_announce", start_announce, NULL, 3600.0, 1);
+ } else {
+ if (eventFind(start_announce, NULL))
+ eventDelete(start_announce, NULL);
+ }
+ eventCleanup();
+ writePidFile(); /* write PID file */
+ debug(1, 1) ("Ready to serve requests.\n");
+ reconfiguring = 0;
+ peerMonitorInit();
+}
+
+static void
+mainRotate(void)
+{
+ icmpClose();
+#if USE_DNSSERVERS
+ dnsShutdown();
+#endif
+ redirectShutdown();
+ locationRewriteShutdown();
+ authenticateShutdown();
+ externalAclShutdown();
+ _db_rotate_log(); /* cache.log */
+ storeDirWriteCleanLogs(1);
+ storeDirSync(); /* Flush pending I/O ops */
+ storeLogRotate(); /* store.log */
+ accessLogRotate(); /* access.log */
+ useragentRotateLog(); /* useragent.log */
+ refererRotateLog(); /* referer.log */
+#if WIP_FWD_LOG
+ fwdLogRotate();
+#endif
+ icmpOpen();
+#if USE_DNSSERVERS
+ dnsInit();
+#endif
+ redirectInit();
+ locationRewriteInit();
+ authenticateInit(&Config.authConfig);
+ externalAclInit();
+}
+
+static void
+setEffectiveUser(void)
+{
+ keepCapabilities();
+ leave_suid(); /* Run as non privilegied user */
+#ifdef _SQUID_OS2_
+ return;
+#endif
+ if (geteuid() == 0) {
+ debug(0, 0) ("Squid is not safe to run as root! If you must\n");
+ debug(0, 0) ("start Squid as root, then you must configure\n");
+ debug(0, 0) ("it to run as a non-priveledged user with the\n");
+ debug(0, 0) ("'cache_effective_user' option in the config file.\n");
+ fatal("Don't run Squid as root, set 'cache_effective_user'!");
+ }
+}
+
+static void
+mainSetCwd(void)
+{
+ char pathbuf[MAXPATHLEN];
+ if (Config.coredump_dir) {
+ if (0 == strcmp("none", Config.coredump_dir)) {
+ (void) 0;
+ } else if (chdir(Config.coredump_dir) == 0) {
+ debug(0, 1) ("Set Current Directory to %s\n", Config.coredump_dir);
+ return;
+ } else {
+ debug(50, 0) ("chdir: %s: %s\n", Config.coredump_dir, xstrerror());
+ }
+ }
+ /* If we don't have coredump_dir or couldn't cd there, report current dir */
+ if (getcwd(pathbuf, MAXPATHLEN)) {
+ debug(0, 1) ("Current Directory is %s\n", pathbuf);
+ } else {
+ debug(50, 0) ("WARNING: Can't find current directory, getcwd: %s\n", xstrerror());
+ }
+}
+
+static void
+mainInitialize(void)
+{
+ /* chroot if configured to run inside chroot */
+ if (Config.chroot_dir && chroot(Config.chroot_dir)) {
+ fatal("failed to chroot");
+ }
+ if (opt_catch_signals) {
+ squid_signal(SIGSEGV, death, SA_NODEFER | SA_RESETHAND);
+ squid_signal(SIGBUS, death, SA_NODEFER | SA_RESETHAND);
+ }
+ squid_signal(SIGPIPE, SIG_IGN, SA_RESTART);
+ squid_signal(SIGCHLD, sig_child, SA_NODEFER | SA_RESTART);
+
+ setEffectiveUser();
+ if (icpPortNumOverride != 1)
+ Config.Port.icp = (u_short) icpPortNumOverride;
+
+ _db_init(Config.Log.log, Config.debugOptions);
+ fd_open(fileno(debug_log), FD_LOG, Config.Log.log);
+#if MEM_GEN_TRACE
+ log_trace_init("/tmp/squid.alloc");
+#endif
+ debug(1, 0) ("Starting Squid Cache version %s for %s...\n",
+ version_string,
+ CONFIG_HOST_TYPE);
+#ifdef _SQUID_WIN32_
+ if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
+ debug(1, 0) ("Running as %s Windows System Service on %s\n", WIN32_Service_name, WIN32_OS_string);
+ debug(1, 0) ("Service command line is: %s\n", WIN32_Service_Command_Line);
+ } else
+ debug(1, 0) ("Running on %s\n", WIN32_OS_string);
+#endif
+ debug(1, 1) ("Process ID %d\n", (int) getpid());
+ debug(1, 1) ("With %d file descriptors available\n", Squid_MaxFD);
+#ifdef _SQUID_MSWIN_
+ debug(1, 1) ("With %d CRT stdio descriptors available\n", _getmaxstdio());
+ if (WIN32_Socks_initialized)
+ debug(1, 1) ("Windows sockets initialized\n");
+#endif
+
+ comm_select_postinit();
+ if (!configured_once)
+ disk_init(); /* disk_init must go before ipcache_init() */
+ ipcache_init();
+ fqdncache_init();
+ parseEtcHosts();
+#if USE_DNSSERVERS
+ dnsInit();
+#else
+ idnsInit();
+#endif
+ redirectInit();
+ locationRewriteInit();
+ errorMapInit();
+#ifdef HS_FEAT_ICAP
+ icapInit();
+#endif
+ authenticateInit(&Config.authConfig);
+ externalAclInit();
+ useragentOpenLog();
+ refererOpenLog();
+ httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
+ httpReplyInitModule(); /* must go before accepting replies */
+ errorInitialize();
+ accessLogInit();
+#if USE_IDENT
+ identInit();
+#endif
+#ifdef SQUID_SNMP
+ snmpInit();
+#endif
+#if MALLOC_DBG
+ malloc_debug(0, malloc_debug_level);
+#endif
+
+ if (!configured_once) {
+#if USE_UNLINKD
+ unlinkdInit();
+#endif
+ urlInitialize();
+ cachemgrInit();
+ statInit();
+ storeInit();
+ mainSetCwd();
+ /* after this point we want to see the mallinfo() output */
+ do_mallinfo = 1;
+ mimeInit(Config.mimeTablePathname);
+ pconnInit();
+ refreshInit();
+#if DELAY_POOLS
+ delayPoolsInit();
+#endif
+ fwdInit();
+ }
+#if USE_WCCP
+ wccpInit();
+#endif
+#if USE_WCCPv2
+ wccp2Init();
+#endif
+ serverConnectionsOpen();
+ neighbors_init();
+ if (Config.chroot_dir)
+ no_suid();
+ if (!configured_once)
+ writePidFile(); /* write PID file */
+
+#ifdef _SQUID_LINUX_THREADS_
+ squid_signal(SIGQUIT, rotate_logs, SA_RESTART);
+ squid_signal(SIGTRAP, sigusr2_handle, SA_RESTART);
+#else
+ squid_signal(SIGUSR1, rotate_logs, SA_RESTART);
+ squid_signal(SIGUSR2, sigusr2_handle, SA_RESTART);
+#endif
+ squid_signal(SIGHUP, reconfigure, SA_RESTART);
+ squid_signal(SIGTERM, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
+ squid_signal(SIGINT, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
+ memCheckInit();
+ debug(1, 1) ("Ready to serve requests.\n");
+ if (!configured_once) {
+ eventAdd("storeMaintain", storeMaintainSwapSpace, NULL, 1.0, 1);
+ if (Config.onoff.announce)
+ eventAdd("start_announce", start_announce, NULL, 3600.0, 1);
+ eventAdd("ipcache_purgelru", ipcache_purgelru, NULL, 10.0, 1);
+ eventAdd("fqdncache_purgelru", fqdncache_purgelru, NULL, 15.0, 1);
+ }
+ configured_once = 1;
+}
+
+#if USE_WIN32_SERVICE
+/* When USE_WIN32_SERVICE is defined, the main function is placed in win32.c */
+void WINAPI
+SquidWinSvcMain(int argc, char **argv)
+{
+ SquidMain(argc, argv);
+}
+
+int
+SquidMain(int argc, char **argv)
+#else
+int
+main(int argc, char **argv)
+#endif
+{
+ int errcount = 0;
+ int loop_delay;
+#ifdef _SQUID_WIN32_
+ int WIN32_init_err;
+#endif
+
+#if HAVE_SBRK
+ sbrk_start = sbrk(0);
+#endif
+
+ debug_log = stderr;
+
+#ifdef _SQUID_WIN32_
+ if ((WIN32_init_err = WIN32_Subsystem_Init(&argc, &argv)))
+ return WIN32_init_err;
+#endif
+
+ /* call mallopt() before anything else */
+#if HAVE_MALLOPT
+#ifdef M_GRAIN
+ /* Round up all sizes to a multiple of this */
+ mallopt(M_GRAIN, 16);
+#endif
+#ifdef M_MXFAST
+ /* biggest size that is considered a small block */
+ mallopt(M_MXFAST, 256);
+#endif
+#ifdef M_NBLKS
+ /* allocate this many small blocks at once */
+ mallopt(M_NLBLKS, 32);
+#endif
+#endif /* HAVE_MALLOPT */
+
+ memset(&local_addr, '\0', sizeof(struct in_addr));
+ safe_inet_addr(localhost, &local_addr);
+ memset(&any_addr, '\0', sizeof(struct in_addr));
+ safe_inet_addr("0.0.0.0", &any_addr);
+ memset(&no_addr, '\0', sizeof(struct in_addr));
+ safe_inet_addr("255.255.255.255", &no_addr);
+ squid_srandom(time(NULL));
+
+ getCurrentTime();
+ squid_start = current_time;
+ failure_notify = fatal_dump;
+
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ WIN32_svcstatusupdate(SERVICE_START_PENDING, 10000);
+#endif
+ mainParseOptions(argc, argv);
+
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ if (opt_install_service) {
+ WIN32_InstallService();
+ return 0;
+ }
+ if (opt_remove_service) {
+ WIN32_RemoveService();
+ return 0;
+ }
+ if (opt_command_line) {
+ WIN32_SetServiceCommandLine();
+ return 0;
+ }
+#endif
+
+ /* parse configuration file
+ * note: in "normal" case this used to be called from mainInitialize() */
+ {
+ int parse_err;
+ if (!ConfigFile)
+ ConfigFile = xstrdup(DefaultConfigFile);
+ assert(!configured_once);
+#if USE_LEAKFINDER
+ leakInit();
+#endif
+ memInit();
+ cbdataInit();
+ eventInit(); /* eventInit() is required for config parsing */
+ storeFsInit(); /* required for config parsing */
+ authenticateSchemeInit(); /* required for config parsing */
+ parse_err = parseConfigFile(ConfigFile);
+
+ if (opt_parse_cfg_only)
+ return parse_err;
+ }
+ setUmask(Config.umask);
+ if (-1 == opt_send_signal)
+ if (checkRunningPid())
+ exit(1);
+
+ /* Make sure the OS allows core dumps if enabled in squid.conf */
+ enableCoredumps();
+
+#if TEST_ACCESS
+ comm_init();
+ comm_select_init();
+ mainInitialize();
+ test_access();
+ return 0;
+#endif
+
+ /* send signal to running copy and exit */
+ if (opt_send_signal != -1) {
+ /* chroot if configured to run inside chroot */
+ if (Config.chroot_dir) {
+ if (chroot(Config.chroot_dir))
+ fatal("failed to chroot");
+ no_suid();
+ } else {
+ leave_suid();
+ }
+ sendSignal();
+ /* NOTREACHED */
+ }
+ if (opt_create_swap_dirs) {
+ /* chroot if configured to run inside chroot */
+ if (Config.chroot_dir && chroot(Config.chroot_dir)) {
+ fatal("failed to chroot");
+ }
+ setEffectiveUser();
+ debug(0, 0) ("Creating Swap Directories\n");
+ storeCreateSwapDirectories();
+ return 0;
+ }
+ if (!opt_no_daemon)
+ watch_child(argv);
+ setMaxFD();
+
+ /* init comm module */
+ comm_init();
+ comm_select_init();
+
+ if (opt_no_daemon) {
+ /* we have to init fdstat here. */
+ fd_open(0, FD_LOG, "stdin");
+ fd_open(1, FD_LOG, "stdout");
+ fd_open(2, FD_LOG, "stderr");
+ }
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ WIN32_svcstatusupdate(SERVICE_START_PENDING, 10000);
+#endif
+ mainInitialize();
+
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ WIN32_svcstatusupdate(SERVICE_RUNNING, 0);
+#endif
+
+ /* main loop */
+ for (;;) {
+ if (do_reconfigure) {
+ mainReconfigure();
+ do_reconfigure = 0;
+ } else if (do_rotate) {
+ mainRotate();
+ do_rotate = 0;
+ } else if (do_shutdown) {
+ time_t wait = do_shutdown > 0 ? (int) Config.shutdownLifetime : 0;
+ debug(1, 1) ("Preparing for shutdown after %d requests\n",
+ statCounter.client_http.requests);
+ debug(1, 1) ("Waiting %d seconds for active connections to finish\n",
+ (int) wait);
+ do_shutdown = 0;
+ shutting_down = 1;
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ WIN32_svcstatusupdate(SERVICE_STOP_PENDING, (wait + 1) * 1000);
+#endif
+ serverConnectionsClose();
+ eventAdd("SquidShutdown", SquidShutdown, NULL, (double) (wait + 1), 1);
+ }
+ eventRun();
+ if ((loop_delay = eventNextTime()) < 0)
+ loop_delay = 0;
+ if (debug_log_flush() && loop_delay > 1000)
+ loop_delay = 1000;
+ switch (comm_select(loop_delay)) {
+ case COMM_OK:
+ errcount = 0; /* reset if successful */
+ break;
+ case COMM_ERROR:
+ errcount++;
+ debug(1, 0) ("Select loop Error. Retry %d\n", errcount);
+ if (errcount == 10)
+ fatal_dump("Select Loop failed!");
+ break;
+ case COMM_TIMEOUT:
+ break;
+ case COMM_SHUTDOWN:
+ SquidShutdown(NULL);
+ break;
+ default:
+ fatal_dump("MAIN: Internal error -- this should never happen.");
+ break;
+ }
+ }
+ /* NOTREACHED */
+ return 0;
+}
+
+static void
+sendSignal(void)
+{
+ pid_t pid;
+ debug_log = stderr;
+ pid = readPidFile();
+ if (pid > 1) {
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ if (opt_signal_service)
+ WIN32_sendSignal(opt_send_signal);
+ else {
+#endif
+#if defined(_SQUID_MSWIN_) && defined(USE_WIN32_SERVICE)
+ fprintf(stderr, "%s: ERROR: Could not send ", appname);
+ fprintf(stderr, "signal to Squid Service:\n");
+ fprintf(stderr, "missing -n command line switch.\n");
+#else
+ if (kill(pid, opt_send_signal) &&
+ /* ignore permissions if just running check */
+ !(opt_send_signal == 0 && errno == EPERM)) {
+ fprintf(stderr, "%s: ERROR: Could not send ", appname);
+ fprintf(stderr, "signal %d to process %d: %s\n",
+ opt_send_signal, (int) pid, xstrerror());
+#endif
+ exit(1);
+ }
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_CYGWIN_)
+ }
+#endif
+ } else {
+ fprintf(stderr, "%s: ERROR: No running copy\n", appname);
+ exit(1);
+ }
+ /* signal successfully sent */
+ exit(0);
+}
+
+#ifndef _SQUID_MSWIN_
+/*
+ * This function is run when Squid is in daemon mode, just
+ * before the parent forks and starts up the child process.
+ * It can be used for admin-specific tasks, such as notifying
+ * someone that Squid is (re)started.
+ */
+static void
+mainStartScript(const char *prog)
+{
+ char script[SQUID_MAXPATHLEN];
+ char *t;
+ size_t sl = 0;
+ pid_t cpid;
+ pid_t rpid;
+ xstrncpy(script, prog, MAXPATHLEN);
+ if ((t = strrchr(script, '/'))) {
+ *(++t) = '\0';
+ sl = strlen(script);
+ }
+ xstrncpy(&script[sl], squid_start_script, MAXPATHLEN - sl);
+ if ((cpid = fork()) == 0) {
+ /* child */
+ execl(script, squid_start_script, NULL);
+ _exit(0);
+ } else {
+ do {
+#ifdef _SQUID_NEXT_
+ union wait status;
+ rpid = wait3(&status, 0, NULL);
+#else
+ int status;
+ rpid = waitpid(-1, &status, 0);
+#endif
+ } while (rpid != cpid);
+ }
+}
+#endif
+
+static int
+checkRunningPid(void)
+{
+ pid_t pid;
+ debug_log = stderr;
+ if (strcmp(Config.pidFilename, "none") == 0) {
+ debug(0, 1) ("No pid_filename specified. Trusting you know what you are doing.\n");
+ return 0;
+ }
+ pid = readPidFile();
+ if (pid < 2)
+ return 0;
+ if (kill(pid, 0) < 0)
+ return 0;
+ debug(0, 0) ("Squid is already running! Process ID %ld\n", (long int) pid);
+ return 1;
+}
+
+static void
+watch_child(char *argv[])
+{
+#ifndef _SQUID_MSWIN_
+ char *prog;
+ int failcount = 0;
+ time_t start;
+ time_t stop;
+#ifdef _SQUID_NEXT_
+ union wait status;
+#else
+ int status;
+#endif
+ pid_t pid;
+#ifdef TIOCNOTTY
+ int i;
+#endif
+ int nullfd;
+ if (*(argv[0]) == '(')
+ return;
+ openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
+ if ((pid = fork()) < 0)
+ syslog(LOG_ALERT, "fork failed: %s", xstrerror());
+ else if (pid > 0)
+ exit(0);
+ if (setsid() < 0)
+ syslog(LOG_ALERT, "setsid failed: %s", xstrerror());
+ closelog();
+#ifdef TIOCNOTTY
+ if ((i = open("/dev/tty", O_RDWR | O_TEXT)) >= 0) {
+ ioctl(i, TIOCNOTTY, NULL);
+ close(i);
+ }
+#endif
+
+
+ /*
+ * RBCOLLINS - if cygwin stackdumps when squid is run without
+ * -N, check the cygwin1.dll version, it needs to be AT LEAST
+ * 1.1.3. execvp had a bit overflow error in a loop..
+ */
+ /* Connect stdio to /dev/null in daemon mode */
+ nullfd = open(_PATH_DEVNULL, O_RDWR | O_TEXT);
+ if (nullfd < 0)
+ fatalf(_PATH_DEVNULL " %s\n", xstrerror());
+ dup2(nullfd, 0);
+ if (opt_debug_stderr < 0) {
+ dup2(nullfd, 1);
+ dup2(nullfd, 2);
+ }
+ if (nullfd > 2)
+ close(nullfd);
+ for (;;) {
+ mainStartScript(argv[0]);
+ if ((pid = fork()) == 0) {
+ /* child */
+ openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
+ prog = xstrdup(argv[0]);
+ argv[0] = xstrdup("(squid)");
+ execvp(prog, argv);
+ syslog(LOG_ALERT, "execvp failed: %s", xstrerror());
+ }
+ /* parent */
+ openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
+ syslog(LOG_NOTICE, "Squid Parent: child process %d started", pid);
+ time(&start);
+ squid_signal(SIGINT, SIG_IGN, SA_RESTART);
+#ifdef _SQUID_NEXT_
+ pid = wait3(&status, 0, NULL);
+#else
+ pid = waitpid(-1, &status, 0);
+#endif
+ time(&stop);
+ if (WIFEXITED(status)) {
+ syslog(LOG_NOTICE,
+ "Squid Parent: child process %d exited with status %d",
+ pid, WEXITSTATUS(status));
+ } else if (WIFSIGNALED(status)) {
+ syslog(LOG_NOTICE,
+ "Squid Parent: child process %d exited due to signal %d",
+ pid, WTERMSIG(status));
+ } else {
+ syslog(LOG_NOTICE, "Squid Parent: child process %d exited", pid);
+ }
+ if (stop - start < 10)
+ failcount++;
+ else
+ failcount = 0;
+ if (failcount == 5) {
+ syslog(LOG_ALERT, "Exiting due to repeated, frequent failures");
+ exit(1);
+ }
+ if (WIFEXITED(status))
+ if (WEXITSTATUS(status) == 0)
+ exit(0);
+ if (WIFSIGNALED(status)) {
+ switch (WTERMSIG(status)) {
+ case SIGKILL:
+ exit(0);
+ break;
+ default:
+ break;
+ }
+ }
+ squid_signal(SIGINT, SIG_DFL, SA_RESTART);
+ sleep(3);
+ }
+ /* NOTREACHED */
+#endif
+}
+
+static void
+SquidShutdown(void *unused)
+{
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ WIN32_svcstatusupdate(SERVICE_STOP_PENDING, 10000);
+#endif
+ debug(1, 1) ("Shutting down...\n");
+#if USE_DNSSERVERS
+ dnsShutdown();
+#else
+ idnsShutdown();
+#endif
+ redirectShutdown();
+ externalAclShutdown();
+ locationRewriteShutdown();
+ icpConnectionClose();
+#if USE_HTCP
+ htcpSocketClose();
+#endif
+#ifdef SQUID_SNMP
+ snmpConnectionClose();
+#endif
+#if USE_WCCP
+ wccpConnectionClose();
+#endif
+#if USE_WCCPv2
+ wccp2ConnectionClose();
+#endif
+ releaseServerSockets();
+ commCloseAllSockets();
+ authenticateShutdown();
+#if USE_UNLINKD
+ unlinkdClose();
+#endif
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ WIN32_svcstatusupdate(SERVICE_STOP_PENDING, 10000);
+#endif
+ storeDirSync(); /* Flush pending object writes/unlinks */
+ storeDirWriteCleanLogs(0);
+ PrintRusage();
+ dumpMallocStats();
+ storeDirSync(); /* Flush log writes */
+ storeLogClose();
+ accessLogClose();
+ useragentLogClose();
+ refererCloseLog();
+#if WIP_FWD_LOG
+ fwdUninit();
+#endif
+ storeDirSync(); /* Flush log close */
+ storeFsDone();
+#if LEAK_CHECK_MODE
+ configFreeMemory();
+ storeFreeMemory();
+ /*stmemFreeMemory(); */
+ netdbFreeMemory();
+ ipcacheFreeMemory();
+ fqdncacheFreeMemory();
+ asnFreeMemory();
+ clientdbFreeMemory();
+ httpHeaderCleanModule();
+ statFreeMemory();
+ eventFreeMemory();
+ mimeFreeMemory();
+ errorClean();
+#endif
+#if !XMALLOC_TRACE
+ if (opt_no_daemon) {
+ fd_close(0);
+ fd_close(1);
+ fd_close(2);
+ }
+#endif
+ comm_select_shutdown();
+ fdDumpOpen();
+ fdFreeMemory();
+ memClean();
+#if XMALLOC_TRACE
+ xmalloc_find_leaks();
+ debug(1, 0) ("Memory used after shutdown: %d\n", xmalloc_total);
+#endif
+#if MEM_GEN_TRACE
+ log_trace_done();
+#endif
+ if (Config.pidFilename && strcmp(Config.pidFilename, "none") != 0) {
+ enter_suid();
+ safeunlink(Config.pidFilename, 0);
+ leave_suid();
+ }
+ debug(1, 1) ("Squid Cache (Version %s): Exiting normally.\n",
+ version_string);
+ if (debug_log)
+ fclose(debug_log);
+ exit(0);
+}
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/a6/3073a52f6888001b16add8656805b17d squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/a6/3073a52f6888001b16add8656805b17d
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/a6/3073a52f6888001b16add8656805b17d 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/a6/3073a52f6888001b16add8656805b17d 2006-12-10 18:04:47.000000000 +0200
@@ -0,0 +1,1169 @@
+
+/*
+ * $Id: main.c,v 1.392 2006/10/23 11:22:21 hno Exp $
+ *
+ * DEBUG: section 1 Startup and Main Loop
+ * AUTHOR: Harvest Derived
+ *
+ * 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"
+
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+#include
+#include
+static int opt_install_service = FALSE;
+static int opt_remove_service = FALSE;
+static int opt_signal_service = FALSE;
+static int opt_command_line = FALSE;
+extern void WIN32_svcstatusupdate(DWORD, DWORD);
+void WINAPI WIN32_svcHandler(DWORD);
+#endif
+
+/* for error reporting from xmalloc and friends */
+extern void (*failure_notify) (const char *);
+
+static char *opt_syslog_facility = NULL;
+static int icpPortNumOverride = 1; /* Want to detect "-u 0" */
+static int configured_once = 0;
+#if MALLOC_DBG
+static int malloc_debug_level = 0;
+#endif
+static volatile int do_reconfigure = 0;
+static volatile int do_rotate = 0;
+static volatile int do_shutdown = 0;
+
+static void mainRotate(void);
+static void mainReconfigure(void);
+static void mainInitialize(void);
+static void usage(void);
+static void mainParseOptions(int, char **);
+static void sendSignal(void);
+static void serverConnectionsOpen(void);
+static void watch_child(char **);
+static void setEffectiveUser(void);
+#if MEM_GEN_TRACE
+extern void log_trace_done();
+extern void log_trace_init(char *);
+#endif
+static EVH SquidShutdown;
+static void mainSetCwd(void);
+static int checkRunningPid(void);
+
+#ifndef _SQUID_MSWIN_
+static const char *squid_start_script = "squid_start";
+#endif
+
+#if TEST_ACCESS
+#include "test_access.c"
+#endif
+
+static void
+usage(void)
+{
+ fprintf(stderr,
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ "Usage: %s [-hirvzCDFRYX] [-d level] [-s | -l facility] [-f config-file] [-u port] [-k signal] [-n name] [-O command-line]\n"
+#else
+ "Usage: %s [-hvzCDFNRYX] [-d level] [-s | -l facility] [-f config-file] [-u port] [-k signal]\n"
+#endif
+ " -d level Write debugging to stderr also.\n"
+ " -f file Use given config-file instead of\n"
+ " %s\n"
+ " -h Print help message.\n"
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ " -i Installs as a Windows Service (see -n option).\n"
+#endif
+ " -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n"
+ " Parse configuration file, then send signal to \n"
+ " running copy (except -k parse) and exit.\n"
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ " -n name Specify Windows Service name to use for service operations\n"
+ " default is: " _WIN_SQUID_DEFAULT_SERVICE_NAME ".\n"
+ " -r Removes a Windows Service (see -n option).\n"
+#endif
+ " -s | -l facility\n"
+ " Enable logging to syslog.\n"
+ " -u port Specify ICP port number (default: %d), disable with 0.\n"
+ " -v Print version.\n"
+ " -z Create swap directories\n"
+ " -C Do not catch fatal signals.\n"
+ " -D Disable initial DNS tests.\n"
+ " -F Don't serve any requests until store is rebuilt.\n"
+ " -N No daemon mode.\n"
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ " -O options\n"
+ " Set Windows Service Command line options in Registry.\n"
+#endif
+ " -R Do not set REUSEADDR on port.\n"
+ " -S Double-check swap during rebuild.\n"
+ " -X Force full debugging.\n"
+ " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
+ appname, DefaultConfigFile, CACHE_ICP_PORT);
+ exit(1);
+}
+
+static void
+mainParseOptions(int argc, char *argv[])
+{
+ extern char *optarg;
+ int c;
+
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ while ((c = getopt(argc, argv, "CDFO:RSYXd:f:hik:m::n:rsl:u:vz?")) != -1) {
+#else
+ while ((c = getopt(argc, argv, "CDFNRSYXd:f:hk:m::sl:u:vz?")) != -1) {
+#endif
+ switch (c) {
+ case 'C':
+ opt_catch_signals = 0;
+ break;
+ case 'D':
+ opt_dns_tests = 0;
+ break;
+ case 'F':
+ opt_foreground_rebuild = 1;
+ break;
+ case 'N':
+ opt_no_daemon = 1;
+ break;
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ case 'O':
+ opt_command_line = 1;
+ WIN32_Command_Line = xstrdup(optarg);
+ break;
+#endif
+ case 'R':
+ opt_reuseaddr = 0;
+ break;
+ case 'S':
+ opt_store_doublecheck = 1;
+ break;
+ case 'X':
+ /* force full debugging */
+ sigusr2_handle(SIGUSR2);
+ break;
+ case 'Y':
+ opt_reload_hit_only = 1;
+ break;
+ case 'd':
+ opt_debug_stderr = atoi(optarg);
+ break;
+ case 'f':
+ xfree(ConfigFile);
+ ConfigFile = xstrdup(optarg);
+ break;
+ case 'h':
+ usage();
+ break;
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ case 'i':
+ opt_install_service = TRUE;
+ break;
+#endif
+ case 'k':
+ if ((int) strlen(optarg) < 1)
+ usage();
+ if (!strncmp(optarg, "reconfigure", strlen(optarg)))
+ opt_send_signal = SIGHUP;
+ else if (!strncmp(optarg, "rotate", strlen(optarg)))
+#ifdef _SQUID_LINUX_THREADS_
+ opt_send_signal = SIGQUIT;
+#else
+ opt_send_signal = SIGUSR1;
+#endif
+ else if (!strncmp(optarg, "debug", strlen(optarg)))
+#ifdef _SQUID_LINUX_THREADS_
+ opt_send_signal = SIGTRAP;
+#else
+ opt_send_signal = SIGUSR2;
+#endif
+ else if (!strncmp(optarg, "shutdown", strlen(optarg)))
+ opt_send_signal = SIGTERM;
+ else if (!strncmp(optarg, "interrupt", strlen(optarg)))
+ opt_send_signal = SIGINT;
+ else if (!strncmp(optarg, "kill", strlen(optarg)))
+ opt_send_signal = SIGKILL;
+ else if (!strncmp(optarg, "check", strlen(optarg)))
+ opt_send_signal = 0; /* SIGNULL */
+ else if (!strncmp(optarg, "parse", strlen(optarg)))
+ opt_parse_cfg_only = 1; /* parse cfg file only */
+ else
+ usage();
+ break;
+ case 'm':
+ if (optarg) {
+#if MALLOC_DBG
+ malloc_debug_level = atoi(optarg);
+ /* NOTREACHED */
+ break;
+#else
+ fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
+ /* NOTREACHED */
+#endif
+ } else {
+#if XMALLOC_TRACE
+ xmalloc_trace = !xmalloc_trace;
+#else
+ fatal("Need to configure --enable-xmalloc-debug-trace to use -m option");
+#endif
+ }
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ case 'n':
+ xfree(WIN32_Service_name);
+ WIN32_Service_name = xstrdup(optarg);
+ opt_signal_service = TRUE;
+ break;
+ case 'r':
+ opt_remove_service = TRUE;
+ break;
+#endif
+ case 'l':
+ opt_syslog_facility = xstrdup(optarg);
+ case 's':
+#if HAVE_SYSLOG
+ _db_set_syslog(opt_syslog_facility);
+ break;
+#else
+ fatal("Logging to syslog not available on this platform");
+ /* NOTREACHED */
+#endif
+ case 'u':
+ icpPortNumOverride = atoi(optarg);
+ if (icpPortNumOverride < 0)
+ icpPortNumOverride = 0;
+ break;
+ case 'v':
+ printf("Squid Cache: Version %s\nPureSight: ICAP Enabled v 1.50\nconfigure options: %s\n", version_string, SQUID_CONFIGURE_OPTIONS);
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ printf("Compiled as Windows System Service.\n");
+#endif
+ exit(0);
+ /* NOTREACHED */
+ case 'z':
+ opt_create_swap_dirs = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ break;
+ }
+ }
+}
+
+/* ARGSUSED */
+void
+rotate_logs(int sig)
+{
+ do_rotate = 1;
+#ifndef _SQUID_MSWIN_
+#if !HAVE_SIGACTION
+ signal(sig, rotate_logs);
+#endif
+#endif
+}
+
+/* ARGSUSED */
+void
+reconfigure(int sig)
+{
+ do_reconfigure = 1;
+#ifndef _SQUID_MSWIN_
+#if !HAVE_SIGACTION
+ signal(sig, reconfigure);
+#endif
+#endif
+}
+
+void
+shut_down(int sig)
+{
+ do_shutdown = sig == SIGINT ? -1 : 1;
+#ifndef _SQUID_MSWIN_
+#ifdef KILL_PARENT_OPT
+ if (getppid() > 1) {
+ debug(1, 1) ("Killing RunCache, pid %ld\n", (long) getppid());
+ if (kill(getppid(), sig) < 0)
+ debug(1, 1) ("kill %ld: %s\n", (long) getppid(), xstrerror());
+ }
+#endif
+#if SA_RESETHAND == 0
+ signal(SIGTERM, SIG_DFL);
+ signal(SIGINT, SIG_DFL);
+#endif
+#endif
+}
+
+static void
+serverConnectionsOpen(void)
+{
+ clientOpenListenSockets();
+ icpConnectionsOpen();
+#if USE_HTCP
+ htcpInit();
+#endif
+#ifdef SQUID_SNMP
+ snmpConnectionOpen();
+#endif
+#if USE_WCCP
+ wccpConnectionOpen();
+#endif
+#if USE_WCCPv2
+ wccp2ConnectionOpen();
+#endif
+ clientdbInit();
+ icmpOpen();
+ netdbInit();
+ asnInit();
+ peerSelectInit();
+#if USE_CARP
+ carpInit();
+#endif
+ peerSourceHashInit();
+ peerUserHashInit();
+ peerMonitorInit();
+}
+
+void
+serverConnectionsClose(void)
+{
+ assert(shutting_down || reconfiguring);
+ clientHttpConnectionsClose();
+ icpConnectionShutdown();
+#if USE_HTCP
+ htcpSocketShutdown();
+#endif
+ icmpClose();
+#ifdef SQUID_SNMP
+ snmpConnectionShutdown();
+#endif
+#if USE_WCCP
+ wccpConnectionClose();
+#endif
+#if USE_WCCPv2
+ wccp2ConnectionClose();
+#endif
+ asnFreeMemory();
+}
+
+static void
+mainReconfigure(void)
+{
+ debug(1, 1) ("Reconfiguring Squid Cache (version %s)...\n", version_string);
+ reconfiguring = 1;
+ /* Already called serverConnectionsClose and ipcacheShutdownServers() */
+ serverConnectionsClose();
+ icpConnectionClose();
+#if USE_HTCP
+ htcpSocketClose();
+#endif
+#ifdef SQUID_SNMP
+ snmpConnectionClose();
+#endif
+#if USE_DNSSERVERS
+ dnsShutdown();
+#else
+ idnsShutdown();
+#endif
+#ifdef HS_FEAT_ICAP
+ icapClose();
+#endif
+ redirectShutdown();
+ locationRewriteShutdown();
+ authenticateShutdown();
+ externalAclShutdown();
+ storeDirCloseSwapLogs();
+ storeLogClose();
+ accessLogClose();
+ useragentLogClose();
+ refererCloseLog();
+ errorClean();
+ enter_suid(); /* root to read config file */
+ parseConfigFile(ConfigFile);
+ setUmask(Config.umask);
+ setEffectiveUser();
+ _db_init(Config.Log.log, Config.debugOptions);
+ ipcache_restart(); /* clear stuck entries */
+ authenticateUserCacheRestart(); /* clear stuck ACL entries */
+ fqdncache_restart(); /* sigh, fqdncache too */
+ parseEtcHosts();
+ errorInitialize(); /* reload error pages */
+ accessLogInit();
+ storeLogOpen();
+ useragentOpenLog();
+ refererOpenLog();
+#if USE_DNSSERVERS
+ dnsInit();
+#else
+ idnsInit();
+#endif
+ redirectInit();
+ locationRewriteInit();
+#ifdef HS_FEAT_ICAP
+ icapInit();
+#endif
+ authenticateInit(&Config.authConfig);
+ externalAclInit();
+#if USE_WCCP
+ wccpInit();
+#endif
+#if USE_WCCPv2
+ wccp2Init();
+#endif
+ serverConnectionsOpen();
+ neighbors_init();
+ storeDirOpenSwapLogs();
+ mimeInit(Config.mimeTablePathname);
+ if (Config.onoff.announce) {
+ if (!eventFind(start_announce, NULL))
+ eventAdd("start_announce", start_announce, NULL, 3600.0, 1);
+ } else {
+ if (eventFind(start_announce, NULL))
+ eventDelete(start_announce, NULL);
+ }
+ eventCleanup();
+ writePidFile(); /* write PID file */
+ debug(1, 1) ("Ready to serve requests.\n");
+ reconfiguring = 0;
+ peerMonitorInit();
+}
+
+static void
+mainRotate(void)
+{
+ icmpClose();
+#if USE_DNSSERVERS
+ dnsShutdown();
+#endif
+ redirectShutdown();
+ locationRewriteShutdown();
+ authenticateShutdown();
+ externalAclShutdown();
+ _db_rotate_log(); /* cache.log */
+ storeDirWriteCleanLogs(1);
+ storeDirSync(); /* Flush pending I/O ops */
+ storeLogRotate(); /* store.log */
+ accessLogRotate(); /* access.log */
+ useragentRotateLog(); /* useragent.log */
+ refererRotateLog(); /* referer.log */
+#if WIP_FWD_LOG
+ fwdLogRotate();
+#endif
+ icmpOpen();
+#if USE_DNSSERVERS
+ dnsInit();
+#endif
+ redirectInit();
+ locationRewriteInit();
+ authenticateInit(&Config.authConfig);
+ externalAclInit();
+}
+
+static void
+setEffectiveUser(void)
+{
+ keepCapabilities();
+ leave_suid(); /* Run as non privilegied user */
+#ifdef _SQUID_OS2_
+ return;
+#endif
+ if (geteuid() == 0) {
+ debug(0, 0) ("Squid is not safe to run as root! If you must\n");
+ debug(0, 0) ("start Squid as root, then you must configure\n");
+ debug(0, 0) ("it to run as a non-priveledged user with the\n");
+ debug(0, 0) ("'cache_effective_user' option in the config file.\n");
+ fatal("Don't run Squid as root, set 'cache_effective_user'!");
+ }
+}
+
+static void
+mainSetCwd(void)
+{
+ char pathbuf[MAXPATHLEN];
+ if (Config.coredump_dir) {
+ if (0 == strcmp("none", Config.coredump_dir)) {
+ (void) 0;
+ } else if (chdir(Config.coredump_dir) == 0) {
+ debug(0, 1) ("Set Current Directory to %s\n", Config.coredump_dir);
+ return;
+ } else {
+ debug(50, 0) ("chdir: %s: %s\n", Config.coredump_dir, xstrerror());
+ }
+ }
+ /* If we don't have coredump_dir or couldn't cd there, report current dir */
+ if (getcwd(pathbuf, MAXPATHLEN)) {
+ debug(0, 1) ("Current Directory is %s\n", pathbuf);
+ } else {
+ debug(50, 0) ("WARNING: Can't find current directory, getcwd: %s\n", xstrerror());
+ }
+}
+
+static void
+mainInitialize(void)
+{
+ /* chroot if configured to run inside chroot */
+ if (Config.chroot_dir && chroot(Config.chroot_dir)) {
+ fatal("failed to chroot");
+ }
+ if (opt_catch_signals) {
+ squid_signal(SIGSEGV, death, SA_NODEFER | SA_RESETHAND);
+ squid_signal(SIGBUS, death, SA_NODEFER | SA_RESETHAND);
+ }
+ squid_signal(SIGPIPE, SIG_IGN, SA_RESTART);
+ squid_signal(SIGCHLD, sig_child, SA_NODEFER | SA_RESTART);
+
+ setEffectiveUser();
+ if (icpPortNumOverride != 1)
+ Config.Port.icp = (u_short) icpPortNumOverride;
+
+ _db_init(Config.Log.log, Config.debugOptions);
+ fd_open(fileno(debug_log), FD_LOG, Config.Log.log);
+#if MEM_GEN_TRACE
+ log_trace_init("/tmp/squid.alloc");
+#endif
+ debug(1, 0) ("Starting Squid Cache version %s for %s...\n",
+ version_string,
+ CONFIG_HOST_TYPE);
+#ifdef _SQUID_WIN32_
+ if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
+ debug(1, 0) ("Running as %s Windows System Service on %s\n", WIN32_Service_name, WIN32_OS_string);
+ debug(1, 0) ("Service command line is: %s\n", WIN32_Service_Command_Line);
+ } else
+ debug(1, 0) ("Running on %s\n", WIN32_OS_string);
+#endif
+ debug(1, 1) ("Process ID %d\n", (int) getpid());
+ debug(1, 1) ("With %d file descriptors available\n", Squid_MaxFD);
+#ifdef _SQUID_MSWIN_
+ debug(1, 1) ("With %d CRT stdio descriptors available\n", _getmaxstdio());
+ if (WIN32_Socks_initialized)
+ debug(1, 1) ("Windows sockets initialized\n");
+#endif
+
+ comm_select_postinit();
+ if (!configured_once)
+ disk_init(); /* disk_init must go before ipcache_init() */
+ ipcache_init();
+ fqdncache_init();
+ parseEtcHosts();
+#if USE_DNSSERVERS
+ dnsInit();
+#else
+ idnsInit();
+#endif
+ redirectInit();
+ locationRewriteInit();
+ errorMapInit();
+#ifdef HS_FEAT_ICAP
+ icapInit();
+#endif
+ authenticateInit(&Config.authConfig);
+ externalAclInit();
+ useragentOpenLog();
+ refererOpenLog();
+ httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
+ httpReplyInitModule(); /* must go before accepting replies */
+ errorInitialize();
+ accessLogInit();
+#if USE_IDENT
+ identInit();
+#endif
+#ifdef SQUID_SNMP
+ snmpInit();
+#endif
+#if MALLOC_DBG
+ malloc_debug(0, malloc_debug_level);
+#endif
+
+ if (!configured_once) {
+#if USE_UNLINKD
+ unlinkdInit();
+#endif
+ urlInitialize();
+ cachemgrInit();
+ statInit();
+ storeInit();
+ mainSetCwd();
+ /* after this point we want to see the mallinfo() output */
+ do_mallinfo = 1;
+ mimeInit(Config.mimeTablePathname);
+ pconnInit();
+ refreshInit();
+#if DELAY_POOLS
+ delayPoolsInit();
+#endif
+ fwdInit();
+ }
+#if USE_WCCP
+ wccpInit();
+#endif
+#if USE_WCCPv2
+ wccp2Init();
+#endif
+ serverConnectionsOpen();
+ neighbors_init();
+ if (Config.chroot_dir)
+ no_suid();
+ if (!configured_once)
+ writePidFile(); /* write PID file */
+
+#ifdef _SQUID_LINUX_THREADS_
+ squid_signal(SIGQUIT, rotate_logs, SA_RESTART);
+ squid_signal(SIGTRAP, sigusr2_handle, SA_RESTART);
+#else
+ squid_signal(SIGUSR1, rotate_logs, SA_RESTART);
+ squid_signal(SIGUSR2, sigusr2_handle, SA_RESTART);
+#endif
+ squid_signal(SIGHUP, reconfigure, SA_RESTART);
+ squid_signal(SIGTERM, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
+ squid_signal(SIGINT, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
+ memCheckInit();
+ debug(1, 1) ("Ready to serve requests.\n");
+ if (!configured_once) {
+ eventAdd("storeMaintain", storeMaintainSwapSpace, NULL, 1.0, 1);
+ if (Config.onoff.announce)
+ eventAdd("start_announce", start_announce, NULL, 3600.0, 1);
+ eventAdd("ipcache_purgelru", ipcache_purgelru, NULL, 10.0, 1);
+ eventAdd("fqdncache_purgelru", fqdncache_purgelru, NULL, 15.0, 1);
+ }
+ configured_once = 1;
+}
+
+#if USE_WIN32_SERVICE
+/* When USE_WIN32_SERVICE is defined, the main function is placed in win32.c */
+void WINAPI
+SquidWinSvcMain(int argc, char **argv)
+{
+ SquidMain(argc, argv);
+}
+
+int
+SquidMain(int argc, char **argv)
+#else
+int
+main(int argc, char **argv)
+#endif
+{
+ int errcount = 0;
+ int loop_delay;
+#ifdef _SQUID_WIN32_
+ int WIN32_init_err;
+#endif
+
+#if HAVE_SBRK
+ sbrk_start = sbrk(0);
+#endif
+
+ debug_log = stderr;
+
+#ifdef _SQUID_WIN32_
+ if ((WIN32_init_err = WIN32_Subsystem_Init(&argc, &argv)))
+ return WIN32_init_err;
+#endif
+
+ /* call mallopt() before anything else */
+#if HAVE_MALLOPT
+#ifdef M_GRAIN
+ /* Round up all sizes to a multiple of this */
+ mallopt(M_GRAIN, 16);
+#endif
+#ifdef M_MXFAST
+ /* biggest size that is considered a small block */
+ mallopt(M_MXFAST, 256);
+#endif
+#ifdef M_NBLKS
+ /* allocate this many small blocks at once */
+ mallopt(M_NLBLKS, 32);
+#endif
+#endif /* HAVE_MALLOPT */
+
+ memset(&local_addr, '\0', sizeof(struct in_addr));
+ safe_inet_addr(localhost, &local_addr);
+ memset(&any_addr, '\0', sizeof(struct in_addr));
+ safe_inet_addr("0.0.0.0", &any_addr);
+ memset(&no_addr, '\0', sizeof(struct in_addr));
+ safe_inet_addr("255.255.255.255", &no_addr);
+ squid_srandom(time(NULL));
+
+ getCurrentTime();
+ squid_start = current_time;
+ failure_notify = fatal_dump;
+
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ WIN32_svcstatusupdate(SERVICE_START_PENDING, 10000);
+#endif
+ mainParseOptions(argc, argv);
+
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ if (opt_install_service) {
+ WIN32_InstallService();
+ return 0;
+ }
+ if (opt_remove_service) {
+ WIN32_RemoveService();
+ return 0;
+ }
+ if (opt_command_line) {
+ WIN32_SetServiceCommandLine();
+ return 0;
+ }
+#endif
+
+ /* parse configuration file
+ * note: in "normal" case this used to be called from mainInitialize() */
+ {
+ int parse_err;
+ if (!ConfigFile)
+ ConfigFile = xstrdup(DefaultConfigFile);
+ assert(!configured_once);
+#if USE_LEAKFINDER
+ leakInit();
+#endif
+ memInit();
+ cbdataInit();
+ eventInit(); /* eventInit() is required for config parsing */
+ storeFsInit(); /* required for config parsing */
+ authenticateSchemeInit(); /* required for config parsing */
+ parse_err = parseConfigFile(ConfigFile);
+
+ if (opt_parse_cfg_only)
+ return parse_err;
+ }
+ setUmask(Config.umask);
+ if (-1 == opt_send_signal)
+ if (checkRunningPid())
+ exit(1);
+
+ /* Make sure the OS allows core dumps if enabled in squid.conf */
+ enableCoredumps();
+
+#if TEST_ACCESS
+ comm_init();
+ comm_select_init();
+ mainInitialize();
+ test_access();
+ return 0;
+#endif
+
+ /* send signal to running copy and exit */
+ if (opt_send_signal != -1) {
+ /* chroot if configured to run inside chroot */
+ if (Config.chroot_dir) {
+ if (chroot(Config.chroot_dir))
+ fatal("failed to chroot");
+ no_suid();
+ } else {
+ leave_suid();
+ }
+ sendSignal();
+ /* NOTREACHED */
+ }
+ if (opt_create_swap_dirs) {
+ /* chroot if configured to run inside chroot */
+ if (Config.chroot_dir && chroot(Config.chroot_dir)) {
+ fatal("failed to chroot");
+ }
+ setEffectiveUser();
+ debug(0, 0) ("Creating Swap Directories\n");
+ storeCreateSwapDirectories();
+ return 0;
+ }
+ if (!opt_no_daemon)
+ watch_child(argv);
+ setMaxFD();
+
+ /* init comm module */
+ comm_init();
+ comm_select_init();
+
+ if (opt_no_daemon) {
+ /* we have to init fdstat here. */
+ fd_open(0, FD_LOG, "stdin");
+ fd_open(1, FD_LOG, "stdout");
+ fd_open(2, FD_LOG, "stderr");
+ }
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ WIN32_svcstatusupdate(SERVICE_START_PENDING, 10000);
+#endif
+ mainInitialize();
+
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ WIN32_svcstatusupdate(SERVICE_RUNNING, 0);
+#endif
+
+ /* main loop */
+ for (;;) {
+ if (do_reconfigure) {
+ mainReconfigure();
+ do_reconfigure = 0;
+ } else if (do_rotate) {
+ mainRotate();
+ do_rotate = 0;
+ } else if (do_shutdown) {
+ time_t wait = do_shutdown > 0 ? (int) Config.shutdownLifetime : 0;
+ debug(1, 1) ("Preparing for shutdown after %d requests\n",
+ statCounter.client_http.requests);
+ debug(1, 1) ("Waiting %d seconds for active connections to finish\n",
+ (int) wait);
+ do_shutdown = 0;
+ shutting_down = 1;
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ WIN32_svcstatusupdate(SERVICE_STOP_PENDING, (wait + 1) * 1000);
+#endif
+ serverConnectionsClose();
+ eventAdd("SquidShutdown", SquidShutdown, NULL, (double) (wait + 1), 1);
+ }
+ eventRun();
+ if ((loop_delay = eventNextTime()) < 0)
+ loop_delay = 0;
+ if (debug_log_flush() && loop_delay > 1000)
+ loop_delay = 1000;
+ switch (comm_select(loop_delay)) {
+ case COMM_OK:
+ errcount = 0; /* reset if successful */
+ break;
+ case COMM_ERROR:
+ errcount++;
+ debug(1, 0) ("Select loop Error. Retry %d\n", errcount);
+ if (errcount == 10)
+ fatal_dump("Select Loop failed!");
+ break;
+ case COMM_TIMEOUT:
+ break;
+ case COMM_SHUTDOWN:
+ SquidShutdown(NULL);
+ break;
+ default:
+ fatal_dump("MAIN: Internal error -- this should never happen.");
+ break;
+ }
+ }
+ /* NOTREACHED */
+ return 0;
+}
+
+static void
+sendSignal(void)
+{
+ pid_t pid;
+ debug_log = stderr;
+ pid = readPidFile();
+ if (pid > 1) {
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ if (opt_signal_service)
+ WIN32_sendSignal(opt_send_signal);
+ else {
+#endif
+#if defined(_SQUID_MSWIN_) && defined(USE_WIN32_SERVICE)
+ fprintf(stderr, "%s: ERROR: Could not send ", appname);
+ fprintf(stderr, "signal to Squid Service:\n");
+ fprintf(stderr, "missing -n command line switch.\n");
+#else
+ if (kill(pid, opt_send_signal) &&
+ /* ignore permissions if just running check */
+ !(opt_send_signal == 0 && errno == EPERM)) {
+ fprintf(stderr, "%s: ERROR: Could not send ", appname);
+ fprintf(stderr, "signal %d to process %d: %s\n",
+ opt_send_signal, (int) pid, xstrerror());
+#endif
+ exit(1);
+ }
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_CYGWIN_)
+ }
+#endif
+ } else {
+ fprintf(stderr, "%s: ERROR: No running copy\n", appname);
+ exit(1);
+ }
+ /* signal successfully sent */
+ exit(0);
+}
+
+#ifndef _SQUID_MSWIN_
+/*
+ * This function is run when Squid is in daemon mode, just
+ * before the parent forks and starts up the child process.
+ * It can be used for admin-specific tasks, such as notifying
+ * someone that Squid is (re)started.
+ */
+static void
+mainStartScript(const char *prog)
+{
+ char script[SQUID_MAXPATHLEN];
+ char *t;
+ size_t sl = 0;
+ pid_t cpid;
+ pid_t rpid;
+ xstrncpy(script, prog, MAXPATHLEN);
+ if ((t = strrchr(script, '/'))) {
+ *(++t) = '\0';
+ sl = strlen(script);
+ }
+ xstrncpy(&script[sl], squid_start_script, MAXPATHLEN - sl);
+ if ((cpid = fork()) == 0) {
+ /* child */
+ execl(script, squid_start_script, NULL);
+ _exit(0);
+ } else {
+ do {
+#ifdef _SQUID_NEXT_
+ union wait status;
+ rpid = wait3(&status, 0, NULL);
+#else
+ int status;
+ rpid = waitpid(-1, &status, 0);
+#endif
+ } while (rpid != cpid);
+ }
+}
+#endif
+
+static int
+checkRunningPid(void)
+{
+ pid_t pid;
+ debug_log = stderr;
+ if (strcmp(Config.pidFilename, "none") == 0) {
+ debug(0, 1) ("No pid_filename specified. Trusting you know what you are doing.\n");
+ return 0;
+ }
+ pid = readPidFile();
+ if (pid < 2)
+ return 0;
+ if (kill(pid, 0) < 0)
+ return 0;
+ debug(0, 0) ("Squid is already running! Process ID %ld\n", (long int) pid);
+ return 1;
+}
+
+static void
+watch_child(char *argv[])
+{
+#ifndef _SQUID_MSWIN_
+ char *prog;
+ int failcount = 0;
+ time_t start;
+ time_t stop;
+#ifdef _SQUID_NEXT_
+ union wait status;
+#else
+ int status;
+#endif
+ pid_t pid;
+#ifdef TIOCNOTTY
+ int i;
+#endif
+ int nullfd;
+ if (*(argv[0]) == '(')
+ return;
+ openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
+ if ((pid = fork()) < 0)
+ syslog(LOG_ALERT, "fork failed: %s", xstrerror());
+ else if (pid > 0)
+ exit(0);
+ if (setsid() < 0)
+ syslog(LOG_ALERT, "setsid failed: %s", xstrerror());
+ closelog();
+#ifdef TIOCNOTTY
+ if ((i = open("/dev/tty", O_RDWR | O_TEXT)) >= 0) {
+ ioctl(i, TIOCNOTTY, NULL);
+ close(i);
+ }
+#endif
+
+
+ /*
+ * RBCOLLINS - if cygwin stackdumps when squid is run without
+ * -N, check the cygwin1.dll version, it needs to be AT LEAST
+ * 1.1.3. execvp had a bit overflow error in a loop..
+ */
+ /* Connect stdio to /dev/null in daemon mode */
+ nullfd = open(_PATH_DEVNULL, O_RDWR | O_TEXT);
+ if (nullfd < 0)
+ fatalf(_PATH_DEVNULL " %s\n", xstrerror());
+ dup2(nullfd, 0);
+ if (opt_debug_stderr < 0) {
+ dup2(nullfd, 1);
+ dup2(nullfd, 2);
+ }
+ if (nullfd > 2)
+ close(nullfd);
+ for (;;) {
+ mainStartScript(argv[0]);
+ if ((pid = fork()) == 0) {
+ /* child */
+ openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
+ prog = xstrdup(argv[0]);
+ argv[0] = xstrdup("(squid)");
+ execvp(prog, argv);
+ syslog(LOG_ALERT, "execvp failed: %s", xstrerror());
+ }
+ /* parent */
+ openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
+ syslog(LOG_NOTICE, "Squid Parent: child process %d started", pid);
+ time(&start);
+ squid_signal(SIGINT, SIG_IGN, SA_RESTART);
+#ifdef _SQUID_NEXT_
+ pid = wait3(&status, 0, NULL);
+#else
+ pid = waitpid(-1, &status, 0);
+#endif
+ time(&stop);
+ if (WIFEXITED(status)) {
+ syslog(LOG_NOTICE,
+ "Squid Parent: child process %d exited with status %d",
+ pid, WEXITSTATUS(status));
+ } else if (WIFSIGNALED(status)) {
+ syslog(LOG_NOTICE,
+ "Squid Parent: child process %d exited due to signal %d",
+ pid, WTERMSIG(status));
+ } else {
+ syslog(LOG_NOTICE, "Squid Parent: child process %d exited", pid);
+ }
+ if (stop - start < 10)
+ failcount++;
+ else
+ failcount = 0;
+ if (failcount == 5) {
+ syslog(LOG_ALERT, "Exiting due to repeated, frequent failures");
+ exit(1);
+ }
+ if (WIFEXITED(status))
+ if (WEXITSTATUS(status) == 0)
+ exit(0);
+ if (WIFSIGNALED(status)) {
+ switch (WTERMSIG(status)) {
+ case SIGKILL:
+ exit(0);
+ break;
+ default:
+ break;
+ }
+ }
+ squid_signal(SIGINT, SIG_DFL, SA_RESTART);
+ sleep(3);
+ }
+ /* NOTREACHED */
+#endif
+}
+
+static void
+SquidShutdown(void *unused)
+{
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ WIN32_svcstatusupdate(SERVICE_STOP_PENDING, 10000);
+#endif
+ debug(1, 1) ("Shutting down...\n");
+#if USE_DNSSERVERS
+ dnsShutdown();
+#else
+ idnsShutdown();
+#endif
+ redirectShutdown();
+ externalAclShutdown();
+ locationRewriteShutdown();
+ icpConnectionClose();
+#if USE_HTCP
+ htcpSocketClose();
+#endif
+#ifdef SQUID_SNMP
+ snmpConnectionClose();
+#endif
+#if USE_WCCP
+ wccpConnectionClose();
+#endif
+#if USE_WCCPv2
+ wccp2ConnectionClose();
+#endif
+ releaseServerSockets();
+ commCloseAllSockets();
+ authenticateShutdown();
+#if USE_UNLINKD
+ unlinkdClose();
+#endif
+#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
+ WIN32_svcstatusupdate(SERVICE_STOP_PENDING, 10000);
+#endif
+ storeDirSync(); /* Flush pending object writes/unlinks */
+ storeDirWriteCleanLogs(0);
+ PrintRusage();
+ dumpMallocStats();
+ storeDirSync(); /* Flush log writes */
+ storeLogClose();
+ accessLogClose();
+ useragentLogClose();
+ refererCloseLog();
+#if WIP_FWD_LOG
+ fwdUninit();
+#endif
+ storeDirSync(); /* Flush log close */
+ storeFsDone();
+#if LEAK_CHECK_MODE
+ configFreeMemory();
+ storeFreeMemory();
+ /*stmemFreeMemory(); */
+ netdbFreeMemory();
+ ipcacheFreeMemory();
+ fqdncacheFreeMemory();
+ asnFreeMemory();
+ clientdbFreeMemory();
+ httpHeaderCleanModule();
+ statFreeMemory();
+ eventFreeMemory();
+ mimeFreeMemory();
+ errorClean();
+#endif
+#if !XMALLOC_TRACE
+ if (opt_no_daemon) {
+ fd_close(0);
+ fd_close(1);
+ fd_close(2);
+ }
+#endif
+ comm_select_shutdown();
+ fdDumpOpen();
+ fdFreeMemory();
+ memClean();
+#if XMALLOC_TRACE
+ xmalloc_find_leaks();
+ debug(1, 0) ("Memory used after shutdown: %d\n", xmalloc_total);
+#endif
+#if MEM_GEN_TRACE
+ log_trace_done();
+#endif
+ if (Config.pidFilename && strcmp(Config.pidFilename, "none") != 0) {
+ enter_suid();
+ safeunlink(Config.pidFilename, 0);
+ leave_suid();
+ }
+ debug(1, 1) ("Squid Cache (Version %s): Exiting normally.\n",
+ version_string);
+ if (debug_log)
+ fclose(debug_log);
+ exit(0);
+}
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/a8/d0ceef315c88001b16add8656805b17d squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/a8/d0ceef315c88001b16add8656805b17d
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/a8/d0ceef315c88001b16add8656805b17d 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/a8/d0ceef315c88001b16add8656805b17d 2006-12-10 16:10:54.000000000 +0200
@@ -0,0 +1,29 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+# Add inputs and outputs from these tool invocations to the build variables
+C_SRCS += \
+$(ROOT)/auth/basic/auth_basic.c
+
+OBJS += \
+./auth/basic/auth_basic.o
+
+DEPS += \
+${addprefix ./auth/basic/, \
+auth_basic.d \
+}
+
+
+# Each subdirectory must supply rules for building sources it contributes
+auth/basic/%.o: $(ROOT)/auth/basic/%.c
+ @echo 'Building file: $<'
+ @echo 'Invoking: GCC C Compiler'
+ @echo gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $<
+ @gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $< && \
+ echo -n $(@:%.o=%.d) $(dir $@) > $(@:%.o=%.d) && \
+ gcc -MM -MG -P -w -O0 -g3 -Wall -c -fmessage-length=0 $< >> $(@:%.o=%.d)
+ @echo 'Finished building: $<'
+ @echo ' '
+
+
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/c/80d6e2315c88001b16add8656805b17d squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/c/80d6e2315c88001b16add8656805b17d
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/c/80d6e2315c88001b16add8656805b17d 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/c/80d6e2315c88001b16add8656805b17d 2006-12-10 16:10:54.000000000 +0200
@@ -0,0 +1,29 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+# Add inputs and outputs from these tool invocations to the build variables
+C_SRCS += \
+$(ROOT)/auth/negotiate/auth_negotiate.c
+
+OBJS += \
+./auth/negotiate/auth_negotiate.o
+
+DEPS += \
+${addprefix ./auth/negotiate/, \
+auth_negotiate.d \
+}
+
+
+# Each subdirectory must supply rules for building sources it contributes
+auth/negotiate/%.o: $(ROOT)/auth/negotiate/%.c
+ @echo 'Building file: $<'
+ @echo 'Invoking: GCC C Compiler'
+ @echo gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $<
+ @gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $< && \
+ echo -n $(@:%.o=%.d) $(dir $@) > $(@:%.o=%.d) && \
+ gcc -MM -MG -P -w -O0 -g3 -Wall -c -fmessage-length=0 $< >> $(@:%.o=%.d)
+ @echo 'Finished building: $<'
+ @echo ' '
+
+
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/cd/a049c8315c88001b16add8656805b17d squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/cd/a049c8315c88001b16add8656805b17d
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/cd/a049c8315c88001b16add8656805b17d 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/cd/a049c8315c88001b16add8656805b17d 2006-12-10 16:10:54.000000000 +0200
@@ -0,0 +1,35 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+# Add inputs and outputs from these tool invocations to the build variables
+C_SRCS += \
+$(ROOT)/fs/diskd/diskd.c \
+$(ROOT)/fs/diskd/store_dir_diskd.c \
+$(ROOT)/fs/diskd/store_io_diskd.c
+
+OBJS += \
+./fs/diskd/diskd.o \
+./fs/diskd/store_dir_diskd.o \
+./fs/diskd/store_io_diskd.o
+
+DEPS += \
+${addprefix ./fs/diskd/, \
+diskd.d \
+store_dir_diskd.d \
+store_io_diskd.d \
+}
+
+
+# Each subdirectory must supply rules for building sources it contributes
+fs/diskd/%.o: $(ROOT)/fs/diskd/%.c
+ @echo 'Building file: $<'
+ @echo 'Invoking: GCC C Compiler'
+ @echo gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $<
+ @gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $< && \
+ echo -n $(@:%.o=%.d) $(dir $@) > $(@:%.o=%.d) && \
+ gcc -MM -MG -P -w -O0 -g3 -Wall -c -fmessage-length=0 $< >> $(@:%.o=%.d)
+ @echo 'Finished building: $<'
+ @echo ' '
+
+
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/d5/60c68ed15e88001b16add8656805b17d squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/d5/60c68ed15e88001b16add8656805b17d
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/d5/60c68ed15e88001b16add8656805b17d 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/d5/60c68ed15e88001b16add8656805b17d 2006-12-10 16:09:19.000000000 +0200
@@ -0,0 +1,1689 @@
+
+/*
+ * $Id: http.c,v 1.418 2006/10/23 21:34:17 hno Exp $
+ *
+ * DEBUG: section 11 Hypertext Transfer Protocol (HTTP)
+ * AUTHOR: Harvest Derived
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Anonymizing patch by lutz@as-node.jena.thur.de
+ * have a look into http-anon.c to get more informations.
+ */
+
+#include "squid.h"
+
+static const char *const crlf = "\r\n";
+
+static CWCB httpSendComplete;
+static CWCB httpSendRequestEntry;
+
+static PF httpReadReply;
+static void httpSendRequest(HttpStateData *);
+PF httpStateFree;
+static PF httpTimeout;
+static void httpCacheNegatively(StoreEntry *);
+static void httpMakePrivate(StoreEntry *);
+static void httpMakePublic(StoreEntry *);
+static int httpCachableReply(HttpStateData *);
+static void httpMaybeRemovePublic(StoreEntry *, http_status);
+static int peer_supports_connection_pinning(HttpStateData * httpState);
+
+void
+httpStateFree(int fd, void *data)
+{
+ HttpStateData *httpState = data;
+#if DELAY_POOLS
+ if (fd >= 0)
+ delayClearNoDelay(fd);
+#endif
+ if (httpState == NULL)
+ return;
+ if (httpState->body_buf) {
+ requestAbortBody(httpState->orig_request);
+ if (httpState->body_buf) {
+ memFree(httpState->body_buf, MEM_8K_BUF);
+ httpState->body_buf = NULL;
+ }
+ }
+ storeUnlockObject(httpState->entry);
+ if (!memBufIsNull(&httpState->reply_hdr)) {
+ memBufClean(&httpState->reply_hdr);
+ }
+ requestUnlink(httpState->request);
+ requestUnlink(httpState->orig_request);
+ httpState->request = NULL;
+ httpState->orig_request = NULL;
+#if HS_FEAT_ICAP
+ cbdataUnlock(httpState->icap_writer);
+#endif
+ cbdataFree(httpState);
+}
+
+int
+httpCachable(method_t method)
+{
+ /* GET and HEAD are cachable. Others are not. */
+ if (method != METHOD_GET && method != METHOD_HEAD)
+ return 0;
+ /* else cachable */
+ return 1;
+}
+
+static void
+httpTimeout(int fd, void *data)
+{
+ HttpStateData *httpState = data;
+ StoreEntry *entry = httpState->entry;
+ debug(11, 4) ("httpTimeout: FD %d: '%s'\n", fd, storeUrl(entry));
+ if (entry->store_status == STORE_PENDING) {
+ fwdFail(httpState->fwd,
+ errorCon(ERR_READ_TIMEOUT, HTTP_GATEWAY_TIMEOUT, httpState->fwd->request));
+ }
+ comm_close(fd);
+}
+
+/* This object can be cached for a long time */
+static void
+httpMakePublic(StoreEntry * entry)
+{
+ if (EBIT_TEST(entry->flags, ENTRY_CACHABLE))
+ storeSetPublicKey(entry);
+}
+
+/* This object should never be cached at all */
+static void
+httpMakePrivate(StoreEntry * entry)
+{
+ storeExpireNow(entry);
+ storeReleaseRequest(entry); /* delete object when not used */
+ /* storeReleaseRequest clears ENTRY_CACHABLE flag */
+}
+
+/* This object may be negatively cached */
+static void
+httpCacheNegatively(StoreEntry * entry)
+{
+ storeNegativeCache(entry);
+ if (EBIT_TEST(entry->flags, ENTRY_CACHABLE))
+ storeSetPublicKey(entry);
+}
+
+static void
+httpMaybeRemovePublic(StoreEntry * e, http_status status)
+{
+ int remove = 0;
+ int forbidden = 0;
+ StoreEntry *pe;
+ switch (status) {
+ case HTTP_OK:
+ case HTTP_NON_AUTHORITATIVE_INFORMATION:
+ case HTTP_MULTIPLE_CHOICES:
+ case HTTP_MOVED_PERMANENTLY:
+ case HTTP_MOVED_TEMPORARILY:
+ case HTTP_GONE:
+ case HTTP_NOT_FOUND:
+ remove = 1;
+ break;
+ case HTTP_FORBIDDEN:
+ case HTTP_METHOD_NOT_ALLOWED:
+ forbidden = 1;
+ break;
+#if WORK_IN_PROGRESS
+ case HTTP_UNAUTHORIZED:
+ forbidden = 1;
+ break;
+#endif
+ default:
+#if QUESTIONABLE
+ /*
+ * Any 2xx response should eject previously cached entities...
+ */
+ if (status >= 200 && status < 300)
+ remove = 1;
+#endif
+ break;
+ }
+ if (!remove && !forbidden)
+ return;
+ if (EBIT_TEST(e->flags, KEY_PRIVATE)) {
+ assert(e->mem_obj);
+ if (e->mem_obj->request)
+ pe = storeGetPublicByRequest(e->mem_obj->request);
+ else
+ pe = storeGetPublic(e->mem_obj->url, e->mem_obj->method);
+ if (pe != NULL) {
+ assert(e != pe);
+ storeRelease(pe);
+ }
+ }
+ /*
+ * Also remove any cached HEAD response in case the object has
+ * changed.
+ */
+ if (e->mem_obj->request)
+ pe = storeGetPublicByRequestMethod(e->mem_obj->request, METHOD_HEAD);
+ else
+ pe = storeGetPublic(e->mem_obj->url, METHOD_HEAD);
+ if (pe != NULL && e != pe) {
+ storeRelease(pe);
+ }
+ if (forbidden)
+ return;
+ switch (e->mem_obj->method) {
+ case METHOD_PUT:
+ case METHOD_DELETE:
+ case METHOD_PROPPATCH:
+ case METHOD_MKCOL:
+ case METHOD_MOVE:
+ case METHOD_BMOVE:
+ case METHOD_BDELETE:
+ /*
+ * Remove any cached GET object if it is beleived that the
+ * object may have changed as a result of other methods
+ */
+ if (e->mem_obj->request)
+ pe = storeGetPublicByRequestMethod(e->mem_obj->request, METHOD_GET);
+ else
+ pe = storeGetPublic(e->mem_obj->url, METHOD_GET);
+ if (pe != NULL) {
+ assert(e != pe);
+ storeRelease(pe);
+ }
+ break;
+ }
+}
+
+static int
+httpCachableReply(HttpStateData * httpState)
+{
+ HttpReply *rep = httpState->entry->mem_obj->reply;
+ HttpHeader *hdr = &rep->header;
+ const int cc_mask = (rep->cache_control) ? rep->cache_control->mask : 0;
+ const char *v;
+#if HTTP_VIOLATIONS
+ const refresh_t *R = NULL;
+ /* This strange looking define first looks up the frefresh pattern
+ * and then checks if the specified flag is set. The main purpose
+ * of this is to simplify the refresh pattern lookup
+ */
+#define REFRESH_OVERRIDE(flag) \
+ ((R = (R ? R : refreshLimits(httpState->entry->mem_obj->url))) , \
+ (R && R->flags.flag))
+#else
+#define REFRESH_OVERRIDE(field) 0
+#endif
+ if (EBIT_TEST(cc_mask, CC_PRIVATE) && !REFRESH_OVERRIDE(ignore_private))
+ return 0;
+ if (EBIT_TEST(cc_mask, CC_NO_CACHE) && !REFRESH_OVERRIDE(ignore_no_cache))
+ return 0;
+ if (EBIT_TEST(cc_mask, CC_NO_STORE))
+ return 0;
+ if (httpState->request->flags.auth_sent) {
+ /*
+ * Responses to requests with authorization may be cached
+ * only if a Cache-Control: public reply header is present.
+ * RFC 2068, sec 14.9.4
+ */
+ if (!EBIT_TEST(cc_mask, CC_PUBLIC) && !REFRESH_OVERRIDE(ignore_auth))
+ return 0;
+ }
+ /* Pragma: no-cache in _replies_ is not documented in HTTP,
+ * but servers like "Active Imaging Webcast/2.0" sure do use it */
+ if (httpHeaderHas(hdr, HDR_PRAGMA)) {
+ String s = httpHeaderGetList(hdr, HDR_PRAGMA);
+ const int no_cache = strListIsMember(&s, "no-cache", ',');
+ stringClean(&s);
+ if (no_cache && !REFRESH_OVERRIDE(ignore_no_cache))
+ return 0;
+ }
+ /*
+ * The "multipart/x-mixed-replace" content type is used for
+ * continuous push replies. These are generally dynamic and
+ * probably should not be cachable
+ */
+ if ((v = httpHeaderGetStr(hdr, HDR_CONTENT_TYPE)))
+ if (!strncasecmp(v, "multipart/x-mixed-replace", 25))
+ return 0;
+ switch (httpState->entry->mem_obj->reply->sline.status) {
+ /* Responses that are cacheable */
+ case HTTP_OK:
+ case HTTP_NON_AUTHORITATIVE_INFORMATION:
+ case HTTP_MULTIPLE_CHOICES:
+ case HTTP_MOVED_PERMANENTLY:
+ case HTTP_GONE:
+ /*
+ * Don't cache objects that need to be refreshed on next request,
+ * unless we know how to refresh it.
+ */
+ if (!refreshIsCachable(httpState->entry))
+ return 0;
+ /* don't cache objects from peers w/o LMT, Date, or Expires */
+ /* check that is it enough to check headers @?@ */
+ if (rep->date > -1)
+ return 1;
+ else if (rep->last_modified > -1)
+ return 1;
+ else if (!httpState->peer)
+ return 1;
+ /* @?@ (here and 302): invalid expires header compiles to squid_curtime */
+ else if (rep->expires > -1)
+ return 1;
+ else
+ return 0;
+ /* NOTREACHED */
+ break;
+ /* Responses that only are cacheable if the server says so */
+ case HTTP_MOVED_TEMPORARILY:
+ if (rep->expires > -1)
+ return 1;
+ else
+ return 0;
+ /* NOTREACHED */
+ break;
+ /* Errors can be negatively cached */
+ case HTTP_NO_CONTENT:
+ case HTTP_USE_PROXY:
+ case HTTP_BAD_REQUEST:
+ case HTTP_FORBIDDEN:
+ case HTTP_NOT_FOUND:
+ case HTTP_METHOD_NOT_ALLOWED:
+ case HTTP_REQUEST_URI_TOO_LARGE:
+ case HTTP_INTERNAL_SERVER_ERROR:
+ case HTTP_NOT_IMPLEMENTED:
+ case HTTP_BAD_GATEWAY:
+ case HTTP_SERVICE_UNAVAILABLE:
+ case HTTP_GATEWAY_TIMEOUT:
+ return -1;
+ /* NOTREACHED */
+ break;
+ /* Some responses can never be cached */
+ case HTTP_PARTIAL_CONTENT: /* Not yet supported */
+ case HTTP_SEE_OTHER:
+ case HTTP_NOT_MODIFIED:
+ case HTTP_UNAUTHORIZED:
+ case HTTP_PROXY_AUTHENTICATION_REQUIRED:
+ case HTTP_INVALID_HEADER: /* Squid header parsing error */
+ case HTTP_HEADER_TOO_LARGE:
+ default: /* Unknown status code */
+ return 0;
+ /* NOTREACHED */
+ break;
+ }
+ /* NOTREACHED */
+}
+
+/*
+ * For Vary, store the relevant request headers as
+ * virtual headers in the reply
+ * Returns false if the variance cannot be stored
+ */
+const char *
+httpMakeVaryMark(request_t * request, HttpReply * reply)
+{
+ String vary = StringNull, hdr;
+ const char *pos = NULL;
+ const char *item;
+ const char *value;
+ int ilen;
+ String vstr = StringNull;
+
+ stringClean(&vstr);
+ hdr = httpHeaderGetList(&reply->header, HDR_VARY);
+ if (strBuf(hdr))
+ strListAdd(&vary, strBuf(hdr), ',');
+ stringClean(&hdr);
+#if X_ACCELERATOR_VARY
+ hdr = httpHeaderGetList(&reply->header, HDR_X_ACCELERATOR_VARY);
+ if (strBuf(hdr))
+ strListAdd(&vary, strBuf(hdr), ',');
+ stringClean(&hdr);
+#endif
+ while (strListGetItem(&vary, ',', &item, &ilen, &pos)) {
+ char *name = xmalloc(ilen + 1);
+ xstrncpy(name, item, ilen + 1);
+ Tolower(name);
+ if (strcmp(name, "accept-encoding") == 0) {
+ aclCheck_t checklist;
+ memset(&checklist, 0, sizeof(checklist));
+ checklist.request = request;
+ checklist.reply = reply;
+ if (Config.accessList.vary_encoding && aclCheckFast(Config.accessList.vary_encoding, &checklist)) {
+ stringClean(&request->vary_encoding);
+ request->vary_encoding = httpHeaderGetStrOrList(&request->header, HDR_ACCEPT_ENCODING);
+ strCat(request->vary_encoding, "");
+ }
+ }
+ if (strcmp(name, "*") == 0) {
+ /* Can not handle "Vary: *" efficiently, bail out making the response not cached */
+ safe_free(name);
+ stringClean(&vary);
+ stringClean(&vstr);
+ break;
+ }
+ strListAdd(&vstr, name, ',');
+ hdr = httpHeaderGetByName(&request->header, name);
+ safe_free(name);
+ value = strBuf(hdr);
+ if (value) {
+ value = rfc1738_escape_part(value);
+ stringAppend(&vstr, "=\"", 2);
+ stringAppend(&vstr, value, strlen(value));
+ stringAppend(&vstr, "\"", 1);
+ }
+ stringClean(&hdr);
+ }
+ safe_free(request->vary_hdr);
+ safe_free(request->vary_headers);
+ if (strBuf(vary) && strBuf(vstr)) {
+ request->vary_hdr = xstrdup(strBuf(vary));
+ request->vary_headers = xstrdup(strBuf(vstr));
+ }
+ debug(11, 3) ("httpMakeVaryMark: %s\n", strBuf(vstr));
+ stringClean(&vary);
+ stringClean(&vstr);
+ return request->vary_headers;
+}
+
+/* rewrite this later using new interfaces @?@ */
+void
+httpProcessReplyHeader(HttpStateData * httpState, const char *buf, int size)
+{
+ StoreEntry *entry = httpState->entry;
+ size_t hdr_len;
+ size_t hdr_size;
+ HttpReply *reply = entry->mem_obj->reply;
+ Ctx ctx = ctx_enter(entry->mem_obj->url);
+ debug(11, 3) ("httpProcessReplyHeader: key '%s'\n",
+ storeKeyText(entry->hash.key));
+ if (memBufIsNull(&httpState->reply_hdr))
+ memBufDefInit(&httpState->reply_hdr);
+ assert(httpState->reply_hdr_state == 0);
+ memBufAppend(&httpState->reply_hdr, buf, size);
+ hdr_len = httpState->reply_hdr.size;
+ if (hdr_len > 4 && strncmp(httpState->reply_hdr.buf, "HTTP/", 5)) {
+ debug(11, 3) ("httpProcessReplyHeader: Non-HTTP-compliant header: '%s'\n", httpState->reply_hdr.buf);
+ httpState->reply_hdr_state += 2;
+ memBufClean(&httpState->reply_hdr);
+ httpBuildVersion(&reply->sline.version, 0, 9);
+ reply->sline.status = HTTP_INVALID_HEADER;
+ ctx_exit(ctx);
+ return;
+ }
+ hdr_size = headersEnd(httpState->reply_hdr.buf, hdr_len);
+ if (hdr_size)
+ hdr_len = hdr_size;
+ if (hdr_len > Config.maxReplyHeaderSize) {
+ debug(11, 1) ("httpProcessReplyHeader: Too large reply header\n");
+ if (!memBufIsNull(&httpState->reply_hdr))
+ memBufClean(&httpState->reply_hdr);
+ reply->sline.status = HTTP_HEADER_TOO_LARGE;
+ httpState->reply_hdr_state += 2;
+ ctx_exit(ctx);
+ return;
+ }
+ /* headers can be incomplete only if object still arriving */
+ if (!hdr_size) {
+ if (httpState->eof)
+ hdr_size = hdr_len;
+ else {
+ ctx_exit(ctx);
+ return; /* headers not complete */
+ }
+ }
+ safe_free(entry->mem_obj->vary_headers);
+ safe_free(entry->mem_obj->vary_encoding);
+ /* Cut away any excess body data (only needed for debug?) */
+ memBufAppend(&httpState->reply_hdr, "\0", 1);
+ httpState->reply_hdr.buf[hdr_size] = '\0';
+ httpState->reply_hdr_state++;
+ assert(httpState->reply_hdr_state == 1);
+ httpState->reply_hdr_state++;
+ debug(11, 9) ("GOT HTTP REPLY HDR:\n---------\n%s\n----------\n",
+ httpState->reply_hdr.buf);
+ /* Parse headers into reply structure */
+ /* what happens if we fail to parse here? */
+ httpReplyParse(reply, httpState->reply_hdr.buf, hdr_size);
+ if (reply->sline.status >= HTTP_INVALID_HEADER) {
+ debug(11, 3) ("httpProcessReplyHeader: Non-HTTP-compliant header: '%s'\n", httpState->reply_hdr.buf);
+ memBufClean(&httpState->reply_hdr);
+ ctx_exit(ctx);
+ return;
+ }
+ if (!peer_supports_connection_pinning(httpState))
+ httpState->orig_request->flags.no_connection_auth = 1;
+ storeTimestampsSet(entry);
+ /* Check if object is cacheable or not based on reply code */
+ debug(11, 3) ("httpProcessReplyHeader: HTTP CODE: %d\n", reply->sline.status);
+ if (httpHeaderHas(&reply->header, HDR_VARY)
+#if X_ACCELERATOR_VARY
+ || httpHeaderHas(&reply->header, HDR_X_ACCELERATOR_VARY)
+#endif
+ ) {
+ const char *vary = NULL;
+ if (Config.onoff.cache_vary)
+ vary = httpMakeVaryMark(httpState->orig_request, reply);
+ if (!vary) {
+ httpMakePrivate(entry);
+ goto no_cache;
+ }
+ entry->mem_obj->vary_headers = xstrdup(vary);
+ if (strBuf(httpState->orig_request->vary_encoding))
+ entry->mem_obj->vary_encoding = xstrdup(strBuf(httpState->orig_request->vary_encoding));
+ }
+ switch (httpCachableReply(httpState)) {
+ case 1:
+ httpMakePublic(entry);
+ break;
+ case 0:
+ httpMakePrivate(entry);
+ break;
+ case -1:
+ if (Config.negativeTtl > 0)
+ httpCacheNegatively(entry);
+ else
+ httpMakePrivate(entry);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ no_cache:
+ if (reply->cache_control) {
+ if (EBIT_TEST(reply->cache_control->mask, CC_PROXY_REVALIDATE))
+ EBIT_SET(entry->flags, ENTRY_REVALIDATE);
+ else if (EBIT_TEST(reply->cache_control->mask, CC_MUST_REVALIDATE))
+ EBIT_SET(entry->flags, ENTRY_REVALIDATE);
+ }
+ if (neighbors_do_private_keys && !Config.onoff.collapsed_forwarding)
+ httpMaybeRemovePublic(entry, reply->sline.status);
+ if (httpState->flags.keepalive)
+ if (httpState->peer)
+ httpState->peer->stats.n_keepalives_sent++;
+ if (reply->keep_alive) {
+ if (httpState->peer)
+ httpState->peer->stats.n_keepalives_recv++;
+ if (Config.onoff.detect_broken_server_pconns && httpReplyBodySize(httpState->request->method, reply) == -1) {
+ debug(11, 1) ("httpProcessReplyHeader: Impossible keep-alive header from '%s'\n", storeUrl(entry));
+ debug(11, 2) ("GOT HTTP REPLY HDR:\n---------\n%s\n----------\n",
+ httpState->reply_hdr.buf);
+ httpState->flags.keepalive_broken = 1;
+ }
+ }
+ if (reply->date > -1 && !httpState->peer) {
+ int skew = abs(reply->date - squid_curtime);
+ if (skew > 86400)
+ debug(11, 3) ("%s's clock is skewed by %d seconds!\n",
+ httpState->request->host, skew);
+ }
+ ctx_exit(ctx);
+#if HEADERS_LOG
+ headersLog(1, 0, httpState->request->method, reply);
+#endif
+}
+
+static int
+httpPconnTransferDone(HttpStateData * httpState)
+{
+ /* return 1 if we got the last of the data on a persistent connection */
+ 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) {
+ 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 (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 (content_bytes_read < clen + reply->hdr_sz)
+ return 0;
+ /* We got it all */
+ return 1;
+}
+
+/* Small helper function to verify if connection pinning is supported or not
+ */
+static int
+peer_supports_connection_pinning(HttpStateData * httpState)
+{
+ const HttpReply *rep = httpState->entry->mem_obj->reply;
+ const HttpHeader *hdr = &rep->header;
+ const request_t *req = httpState->request;
+ int rc;
+ String header;
+
+ if (!httpState->peer)
+ return 1;
+
+ if (!httpState->peer->connection_auth)
+ return 0;
+
+ if (rep->sline.status != HTTP_UNAUTHORIZED)
+ return 1;
+
+ if (httpState->peer->connection_auth == 1)
+ return 1;
+
+ if (httpState->peer->options.originserver)
+ return 1;
+
+ if (req->flags.pinned)
+ return 1;
+
+ if (!httpHeaderHas(hdr, HDR_PROXY_SUPPORT))
+ return 0;
+
+ header = httpHeaderGetStrOrList(hdr, HDR_PROXY_SUPPORT);
+ /* XXX This ought to be done in a case-insensitive manner */
+ rc = (strStr(header, "Session-Based-Authentication") != NULL);
+ stringClean(&header);
+
+ return rc;
+}
+
+/* This will be called when data is ready to be read from fd. Read until
+ * error or connection closed. */
+/* XXX this function is too long! */
+static void
+httpReadReply(int fd, void *data)
+{
+ HttpStateData *httpState = data;
+ LOCAL_ARRAY(char, buf, SQUID_TCP_SO_RCVBUF);
+ StoreEntry *entry = httpState->entry;
+ const request_t *request = httpState->request;
+ const request_t *orig_request = httpState->orig_request;
+ int len;
+ int bin;
+ int clen;
+ size_t read_sz = SQUID_TCP_SO_RCVBUF;
+ struct in_addr *client_addr = NULL;
+ u_short client_port = 0;
+#if DELAY_POOLS
+ 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;
+ }
+#if DELAY_POOLS
+ /* special "if" only for http (for nodelay proxy conns) */
+ if (delayIsNoDelay(fd))
+ delay_id = 0;
+ 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);
+ debug(11, 5) ("httpReadReply: FD %d: len %d.\n", fd, len);
+ if (len > 0) {
+ fd_bytes(fd, len, FD_READ);
+#if DELAY_POOLS
+ delayBytesIn(delay_id, len);
+#endif
+ kb_incr(&statCounter.server.all.kbytes_in, len);
+ kb_incr(&statCounter.server.http.kbytes_in, len);
+ IOStats.Http.reads++;
+ for (clen = len - 1, bin = 0; clen; bin++)
+ clen >>= 1;
+ IOStats.Http.read_hist[bin]++;
+ }
+#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--);
+ if (len == 0) {
+ /* Continue to read... */
+ /* Timeout NOT increased. This whitespace was from previous reply */
+ commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
+ return;
+ }
+ }
+ if (len < 0) {
+ debug(11, 2) ("httpReadReply: FD %d: read failure: %s.\n",
+ fd, xstrerror());
+ if (ignoreErrno(errno)) {
+ commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
+ } else {
+ ErrorState *err;
+ err = errorCon(ERR_READ_ERROR, HTTP_BAD_GATEWAY, httpState->fwd->request);
+ err->xerrno = errno;
+ fwdFail(httpState->fwd, err);
+ comm_close(fd);
+ }
+ } else if (len == 0 && entry->mem_obj->inmem_hi == 0) {
+ fwdFail(httpState->fwd, errorCon(ERR_ZERO_SIZE_OBJECT, HTTP_BAD_GATEWAY, httpState->fwd->request));
+ httpState->eof = 1;
+ comm_close(fd);
+ } 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
+ * called httpProcessReplyHeader() before, we didn't find
+ * the end of headers, but now we are definately at EOF, so
+ * we want to process the reply headers.
+ */
+ httpProcessReplyHeader(httpState, buf, len);
+ if (entry->mem_obj->reply->sline.status == HTTP_HEADER_TOO_LARGE) {
+ storeEntryReset(entry);
+ fwdFail(httpState->fwd, errorCon(ERR_TOO_BIG, HTTP_BAD_GATEWAY, httpState->fwd->request));
+ httpState->fwd->flags.dont_retry = 1;
+ } else if (entry->mem_obj->reply->sline.status == HTTP_INVALID_HEADER && !(entry->mem_obj->reply->sline.version.major == 0 && entry->mem_obj->reply->sline.version.minor == 9)) {
+ storeEntryReset(entry);
+ fwdFail(httpState->fwd, errorCon(ERR_INVALID_RESP, HTTP_BAD_GATEWAY, httpState->fwd->request));
+ httpState->fwd->flags.dont_retry = 1;
+ } else {
+ fwdComplete(httpState->fwd);
+ }
+ comm_close(fd);
+ return;
+ } else {
+ if (httpState->reply_hdr_state < 2) {
+ httpProcessReplyHeader(httpState, buf, len);
+ if (httpState->reply_hdr_state == 2) {
+ http_status s = entry->mem_obj->reply->sline.status;
+ if (s == HTTP_HEADER_TOO_LARGE) {
+ debug(11, 1) ("WARNING: %s:%d: HTTP header too large\n", __FILE__, __LINE__);
+ storeEntryReset(entry);
+ fwdFail(httpState->fwd, errorCon(ERR_TOO_BIG, HTTP_BAD_GATEWAY, httpState->fwd->request));
+ httpState->fwd->flags.dont_retry = 1;
+ comm_close(fd);
+ return;
+ }
+ if (s == HTTP_INVALID_HEADER && !(entry->mem_obj->reply->sline.version.major == 0 && entry->mem_obj->reply->sline.version.minor == 9)) {
+ storeEntryReset(entry);
+ fwdFail(httpState->fwd, errorCon(ERR_INVALID_RESP, HTTP_BAD_GATEWAY, httpState->fwd->request));
+ httpState->fwd->flags.dont_retry = 1;
+ comm_close(fd);
+ return;
+ }
+#if WIP_FWD_LOG
+ fwdStatus(httpState->fwd, s);
+#endif
+ /*
+ * If its not a reply that we will re-forward, then
+ * allow the client to get it.
+ */
+ if (!fwdReforwardableStatus(s))
+ 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,
+ * in that case, the server FD should already be closed.
+ * there's nothing for us to do.
+ */
+ return;
+ }
+ switch (httpPconnTransferDone(httpState)) {
+ case 1:
+ {
+ int keep_alive = 1;
+ /*
+ * If we didn't send a keep-alive request header, then this
+ * can not be a persistent connection.
+ */
+ if (!httpState->flags.keepalive)
+ keep_alive = 0;
+ /*
+ * If we haven't sent the whole request then this can not be a persistent
+ * connection.
+ */
+ if (!httpState->flags.request_sent) {
+ debug(11, 1) ("httpReadReply: Request not yet fully sent \"%s %s\"\n",
+ RequestMethodStr[orig_request->method],
+ storeUrl(entry));
+ keep_alive = 0;
+ }
+ /*
+ * What does the reply have to say about keep-alive?
+ */
+ if (!entry->mem_obj->reply->keep_alive)
+ keep_alive = 0;
+ /*
+ * Verify that the connection is clean
+ */
+ if (len == read_sz) {
+ statCounter.syscalls.sock.reads++;
+ len = FD_READ_METHOD(fd, buf, SQUID_TCP_SO_RCVBUF);
+ if ((len < 0 && !ignoreErrno(errno)) || len == 0) {
+ keep_alive = 0;
+ } else if (len > 0) {
+ debug(11, Config.onoff.relaxed_header_parser <= 0 || keep_alive ? 1 : 2)
+ ("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
+ if (orig_request->flags.tproxy) {
+ client_addr = &httpState->request->client_addr;
+ }
+#endif
+ /* yes we have to clear all these! */
+ commSetDefer(fd, NULL, NULL);
+ commSetTimeout(fd, -1, NULL, NULL);
+ commSetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0);
+#if DELAY_POOLS
+ delayClearNoDelay(fd);
+#endif
+ comm_remove_close_handler(fd, httpStateFree, httpState);
+ fwdUnregister(fd, httpState->fwd);
+ if (request->flags.pinned) {
+ pinned = 1;
+ } else if (request->flags.connection_auth && request->flags.auth_sent) {
+ pinned = 1;
+ }
+ if (orig_request->pinned_connection && pinned) {
+ clientPinConnection(orig_request->pinned_connection, fd, orig_request, httpState->peer, request->flags.connection_auth);
+ } else if (httpState->peer) {
+ if (httpState->peer->options.originserver)
+ pconnPush(fd, httpState->peer->name, httpState->peer->http_port, httpState->orig_request->host, client_addr, client_port);
+ else
+ pconnPush(fd, httpState->peer->name, httpState->peer->http_port, NULL, client_addr, client_port);
+ } else {
+ pconnPush(fd, request->host, request->port, NULL, client_addr, client_port);
+ }
+ fwdComplete(httpState->fwd);
+ httpState->fd = -1;
+ httpStateFree(fd, httpState);
+ } else {
+ fwdComplete(httpState->fwd);
+ comm_close(fd);
+ }
+ }
+ return;
+ case 0:
+ /* Wait for more data or EOF condition */
+ if (httpState->flags.keepalive_broken) {
+ commSetTimeout(fd, 10, NULL, NULL);
+ } else {
+ commSetTimeout(fd, Config.Timeout.read, NULL, NULL);
+ }
+ commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
+ return;
+ case -1:
+ /* Server is nasty on us. Shut down */
+ debug(11, Config.onoff.relaxed_header_parser <= 0 || entry->mem_obj->reply->keep_alive ? 1 : 2)
+ ("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;
+ default:
+ fatal("Unexpected httpPconnTransferDone() status\n");
+ break;
+ }
+ }
+}
+
+#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
+httpSendComplete(int fd, char *bufnotused, size_t size, int errflag, void *data)
+{
+ HttpStateData *httpState = data;
+ StoreEntry *entry = httpState->entry;
+ debug(11, 5) ("httpSendComplete: FD %d: size %d: errflag %d.\n",
+ fd, (int) size, errflag);
+#if URL_CHECKSUM_DEBUG
+ assert(entry->mem_obj->chksum == url_checksum(entry->mem_obj->url));
+#endif
+ if (size > 0) {
+ fd_bytes(fd, size, FD_WRITE);
+ kb_incr(&statCounter.server.all.kbytes_out, size);
+ kb_incr(&statCounter.server.http.kbytes_out, size);
+ }
+ if (errflag == COMM_ERR_CLOSING)
+ return;
+ if (errflag) {
+ ErrorState *err;
+ err = errorCon(ERR_WRITE_ERROR, HTTP_BAD_GATEWAY, httpState->fwd->request);
+ err->xerrno = errno;
+ fwdFail(httpState->fwd, err);
+ 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, httpState->fwd->request);
+ 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
+ * 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.
+ */
+
+ /* removed in stable5:
+ * commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
+ */
+ commSetTimeout(fd, Config.Timeout.read, httpTimeout, httpState);
+#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;
+}
+
+/*
+ * build request headers and append them to a given MemBuf
+ * used by httpBuildRequestPrefix()
+ * note: calls httpHeaderInit(), the caller is responsible for Clean()-ing
+ */
+void
+httpBuildRequestHeader(request_t * request,
+ request_t * orig_request,
+ StoreEntry * entry,
+ HttpHeader * hdr_out,
+ http_state_flags flags)
+{
+ /* building buffer for complex strings */
+#define BBUF_SZ (MAX_URL+32)
+ LOCAL_ARRAY(char, bbuf, BBUF_SZ);
+ String strConnection = StringNull;
+ const HttpHeader *hdr_in = &orig_request->header;
+ int we_do_ranges;
+ const HttpHeaderEntry *e;
+ String strFwd;
+ HttpHeaderPos pos = HttpHeaderInitPos;
+ String etags = StringNull;
+
+ httpHeaderInit(hdr_out, hoRequest);
+ /* append our IMS header */
+ if (request->lastmod > -1)
+ httpHeaderPutTime(hdr_out, HDR_IF_MODIFIED_SINCE, request->lastmod);
+ if (request->etag) {
+ etags = httpHeaderGetList(hdr_in, HDR_IF_NONE_MATCH);
+ strListAddUnique(&etags, request->etag, ',');
+ } else if (request->etags) {
+ int i;
+ etags = httpHeaderGetList(hdr_in, HDR_IF_NONE_MATCH);
+ for (i = 0; i < request->etags->count; i++)
+ strListAddUnique(&etags, request->etags->items[i], ',');
+ }
+ if (strLen(etags))
+ httpHeaderPutStr(hdr_out, HDR_IF_NONE_MATCH, strBuf(etags));
+ stringClean(&etags);
+ /* decide if we want to do Ranges ourselves
+ * (and fetch the whole object now)
+ * We want to handle Ranges ourselves iff
+ * - we can actually parse client Range specs
+ * - the specs are expected to be simple enough (e.g. no out-of-order ranges)
+ * - reply will be cachable
+ * (If the reply will be uncachable we have to throw it away after
+ * serving this request, so it is better to forward ranges to
+ * the server and fetch only the requested content)
+ */
+ if (NULL == orig_request->range)
+ we_do_ranges = 0;
+ else if (!orig_request->flags.cachable)
+ we_do_ranges = 0;
+ else if (orig_request->flags.auth)
+ we_do_ranges = 0;
+ else if (httpHdrRangeOffsetLimit(orig_request->range))
+ we_do_ranges = 0;
+ else
+ we_do_ranges = 1;
+ debug(11, 8) ("httpBuildRequestHeader: range specs: %p, cachable: %d; we_do_ranges: %d\n",
+ orig_request->range, orig_request->flags.cachable, we_do_ranges);
+
+ strConnection = httpHeaderGetList(hdr_in, HDR_CONNECTION);
+ while ((e = httpHeaderGetEntry(hdr_in, &pos))) {
+ debug(11, 5) ("httpBuildRequestHeader: %s: %s\n",
+ strBuf(e->name), strBuf(e->value));
+ if (!httpRequestHdrAllowed(e, &strConnection)) {
+ debug(11, 2) ("'%s' header denied by anonymize_headers configuration\n",
+ strBuf(e->name));
+ continue;
+ }
+ switch (e->id) {
+ case HDR_PROXY_AUTHORIZATION:
+ /* Only pass on proxy authentication to peers for which
+ * authentication forwarding is explicitly enabled
+ */
+ if (flags.proxying && orig_request->peer_login && strcmp(orig_request->peer_login, "PASS") == 0) {
+ httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
+ if (request->flags.connection_proxy_auth)
+ request->flags.pinned = 1;
+ }
+ break;
+ case HDR_AUTHORIZATION:
+ /* Pass on WWW authentication.
+ */
+ if (!flags.originpeer) {
+ httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
+ if (orig_request->flags.connection_auth)
+ orig_request->flags.pinned = 1;
+ } else {
+ /* In accelerators, only forward authentication if enabled
+ * (see also below for proxy->server authentication)
+ */
+ if (orig_request->peer_login && (strcmp(orig_request->peer_login, "PASS") == 0 || strcmp(orig_request->peer_login, "PROXYPASS") == 0)) {
+ httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
+ if (orig_request->flags.connection_auth)
+ orig_request->flags.pinned = 1;
+ }
+ }
+ break;
+ case HDR_HOST:
+ /*
+ * Normally Squid rewrites the Host: header.
+ * However, there is one case when we don't: If the URL
+ * went through our redirector and the admin configured
+ * 'redir_rewrites_host' to be off.
+ */
+ if (orig_request->peer_domain)
+ httpHeaderPutStr(hdr_out, HDR_HOST, orig_request->peer_domain);
+ else if (request->flags.redirected && !Config.onoff.redir_rewrites_host)
+ httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
+ else {
+ /* use port# only if not default */
+ if (orig_request->port == urlDefaultPort(orig_request->protocol)) {
+ httpHeaderPutStr(hdr_out, HDR_HOST, orig_request->host);
+ } else {
+ httpHeaderPutStrf(hdr_out, HDR_HOST, "%s:%d",
+ orig_request->host, (int) orig_request->port);
+ }
+ }
+ break;
+ case HDR_IF_MODIFIED_SINCE:
+ /* append unless we added our own;
+ * note: at most one client's ims header can pass through */
+ if (!httpHeaderHas(hdr_out, HDR_IF_MODIFIED_SINCE))
+ httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
+ break;
+ case HDR_IF_NONE_MATCH:
+ /* append unless we added our own;
+ * note: at most one client's ims header can pass through */
+ if (!httpHeaderHas(hdr_out, HDR_IF_NONE_MATCH))
+ httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
+ break;
+ case HDR_MAX_FORWARDS:
+ if (orig_request->method == METHOD_TRACE) {
+ /* sacrificing efficiency over clarity, etc. */
+ const int hops = httpHeaderGetInt(hdr_in, HDR_MAX_FORWARDS);
+ if (hops > 0)
+ httpHeaderPutInt(hdr_out, HDR_MAX_FORWARDS, hops - 1);
+ }
+ break;
+ case HDR_X_FORWARDED_FOR:
+ if (!opt_forwarded_for)
+ httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
+ break;
+ case HDR_RANGE:
+ case HDR_IF_RANGE:
+ case HDR_REQUEST_RANGE:
+ if (!we_do_ranges)
+ httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
+ break;
+ case HDR_VIA:
+ /* If Via is disabled then forward any received header as-is */
+ if (!Config.onoff.via)
+ httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
+ break;
+ case HDR_PROXY_CONNECTION:
+ case HDR_CONNECTION:
+ case HDR_CACHE_CONTROL:
+ /* append these after the loop if needed */
+ break;
+ case HDR_FRONT_END_HTTPS:
+ if (!flags.front_end_https)
+ httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
+ break;
+ default:
+ /* pass on all other header fields */
+ httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
+ }
+ }
+
+ /* append Via */
+ if (Config.onoff.via) {
+ String strVia = httpHeaderGetList(hdr_in, HDR_VIA);
+ snprintf(bbuf, BBUF_SZ, "%d.%d %s",
+ orig_request->http_ver.major,
+ orig_request->http_ver.minor, ThisCache);
+ strListAdd(&strVia, bbuf, ',');
+ httpHeaderPutStr(hdr_out, HDR_VIA, strBuf(strVia));
+ stringClean(&strVia);
+ }
+ /* append X-Forwarded-For */
+ if (opt_forwarded_for) {
+ strFwd = httpHeaderGetList(hdr_in, HDR_X_FORWARDED_FOR);
+ strListAdd(&strFwd,
+ (((orig_request->client_addr.s_addr != no_addr.s_addr) && opt_forwarded_for) ?
+ inet_ntoa(orig_request->client_addr) : "unknown"), ',');
+ httpHeaderPutStr(hdr_out, HDR_X_FORWARDED_FOR, strBuf(strFwd));
+ stringClean(&strFwd);
+ }
+ /* append Host if not there already */
+ if (!httpHeaderHas(hdr_out, HDR_HOST)) {
+ if (orig_request->peer_domain) {
+ httpHeaderPutStr(hdr_out, HDR_HOST, orig_request->peer_domain);
+ } else if (orig_request->port == urlDefaultPort(orig_request->protocol)) {
+ /* use port# only if not default */
+ httpHeaderPutStr(hdr_out, HDR_HOST, orig_request->host);
+ } else {
+ httpHeaderPutStrf(hdr_out, HDR_HOST, "%s:%d",
+ orig_request->host, (int) orig_request->port);
+ }
+ }
+ /* append Authorization if known in URL, not in header and going direct */
+ if (!httpHeaderHas(hdr_out, HDR_AUTHORIZATION)) {
+ if (!request->flags.proxying) {
+ if (*request->login) {
+ httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %s",
+ base64_encode(request->login));
+ } else if (orig_request->extacl_user && orig_request->extacl_passwd) {
+ char loginbuf[256];
+ snprintf(loginbuf, sizeof(loginbuf), "%s:%s", orig_request->extacl_user, orig_request->extacl_passwd);
+ httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %s",
+ base64_encode(loginbuf));
+ }
+ }
+ }
+ /* append Proxy-Authorization if configured for peer, and proxying */
+ if (request->flags.proxying && orig_request->peer_login &&
+ !httpHeaderHas(hdr_out, HDR_PROXY_AUTHORIZATION)) {
+ if (*orig_request->peer_login == '*') {
+ /* Special mode, to pass the username to the upstream cache */
+ char loginbuf[256];
+ const char *username = "-";
+ if (orig_request->auth_user_request)
+ username = authenticateUserRequestUsername(orig_request->auth_user_request);
+ else if (orig_request->extacl_user)
+ username = orig_request->extacl_user;
+ snprintf(loginbuf, sizeof(loginbuf), "%s%s", username, orig_request->peer_login + 1);
+ httpHeaderPutStrf(hdr_out, HDR_PROXY_AUTHORIZATION, "Basic %s",
+ base64_encode(loginbuf));
+ } else if (strcmp(orig_request->peer_login, "PASS") == 0) {
+ if (orig_request->extacl_user && orig_request->extacl_passwd) {
+ char loginbuf[256];
+ snprintf(loginbuf, sizeof(loginbuf), "%s:%s", orig_request->extacl_user, orig_request->extacl_passwd);
+ httpHeaderPutStrf(hdr_out, HDR_PROXY_AUTHORIZATION, "Basic %s",
+ base64_encode(loginbuf));
+ }
+ } else if (strcmp(orig_request->peer_login, "PROXYPASS") == 0) {
+ /* Nothing to do */
+ } else {
+ httpHeaderPutStrf(hdr_out, HDR_PROXY_AUTHORIZATION, "Basic %s",
+ base64_encode(orig_request->peer_login));
+ }
+ }
+ /* append WWW-Authorization if configured for peer */
+ if (flags.originpeer && orig_request->peer_login &&
+ !httpHeaderHas(hdr_out, HDR_AUTHORIZATION)) {
+ if (strcmp(orig_request->peer_login, "PASS") == 0) {
+ /* No credentials to forward.. (should have been done above if available) */
+ } else if (strcmp(orig_request->peer_login, "PROXYPASS") == 0) {
+ /* Special mode, convert proxy authentication to WWW authentication
+ * (also applies to cookie authentication)
+ */
+ const char *auth = httpHeaderGetStr(hdr_in, HDR_PROXY_AUTHORIZATION);
+ if (auth && strncasecmp(auth, "basic ", 6) == 0) {
+ httpHeaderPutStr(hdr_out, HDR_AUTHORIZATION, auth);
+ if (orig_request->flags.connection_auth)
+ orig_request->flags.pinned = 1;
+ } else if (orig_request->extacl_user && orig_request->extacl_passwd) {
+ char loginbuf[256];
+ snprintf(loginbuf, sizeof(loginbuf), "%s:%s", orig_request->extacl_user, orig_request->extacl_passwd);
+ httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %s",
+ base64_encode(loginbuf));
+ }
+ } else if (*orig_request->peer_login == '*') {
+ /* Special mode, to pass the username to the upstream cache */
+ char loginbuf[256];
+ const char *username = "-";
+ if (orig_request->auth_user_request)
+ username = authenticateUserRequestUsername(orig_request->auth_user_request);
+ else if (orig_request->extacl_user)
+ username = orig_request->extacl_user;
+ snprintf(loginbuf, sizeof(loginbuf), "%s%s", username, orig_request->peer_login + 1);
+ httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %s",
+ base64_encode(loginbuf));
+ } else {
+ /* Fixed login string */
+ httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %s",
+ base64_encode(orig_request->peer_login));
+ }
+ }
+ /* append Cache-Control, add max-age if not there already */
+ {
+ HttpHdrCc *cc = httpHeaderGetCc(hdr_in);
+ if (!cc)
+ cc = httpHdrCcCreate();
+ 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))
+ EBIT_SET(cc->mask, CC_NO_CACHE);
+ /* Enforce sibling relations */
+ if (flags.only_if_cached)
+ EBIT_SET(cc->mask, CC_ONLY_IF_CACHED);
+ httpHeaderPutCc(hdr_out, cc);
+ httpHdrCcDestroy(cc);
+ }
+ /* maybe append Connection: keep-alive */
+ if (flags.keepalive || request->flags.pinned) {
+ if (flags.proxying) {
+ httpHeaderPutStr(hdr_out, HDR_PROXY_CONNECTION, "keep-alive");
+ } else {
+ httpHeaderPutStr(hdr_out, HDR_CONNECTION, "keep-alive");
+ }
+ }
+ /* append Front-End-Https */
+ if (flags.front_end_https) {
+ if (flags.front_end_https == 1 || request->protocol == PROTO_HTTPS)
+ httpHeaderPutStr(hdr_out, HDR_FRONT_END_HTTPS, "On");
+ }
+ /* Now mangle the headers. */
+ httpHdrMangleList(hdr_out, orig_request);
+ stringClean(&strConnection);
+}
+
+/* build request prefix and append it to a given MemBuf;
+ * return the length of the prefix */
+int
+httpBuildRequestPrefix(request_t * request,
+ request_t * orig_request,
+ StoreEntry * entry,
+ MemBuf * mb,
+ http_state_flags flags)
+{
+ const int offset = mb->size;
+ memBufPrintf(mb, "%s %s HTTP/1.0\r\n",
+ RequestMethodStr[request->method],
+ strLen(request->urlpath) ? strBuf(request->urlpath) : "/");
+ /* build and pack headers */
+ {
+ HttpHeader hdr;
+ Packer p;
+ httpBuildRequestHeader(request, orig_request, entry, &hdr, flags);
+ if (request->flags.pinned && request->flags.connection_auth)
+ request->flags.auth_sent = 1;
+ else
+ request->flags.auth_sent = httpHeaderHas(&hdr, HDR_AUTHORIZATION);
+ packerToMemInit(&p, mb);
+ httpHeaderPackInto(&hdr, &p);
+ httpHeaderClean(&hdr);
+ packerClean(&p);
+ }
+ /* append header terminator */
+ memBufAppend(mb, crlf, 2);
+ return mb->size - offset;
+}
+/* This will be called when connect completes. Write request. */
+static void
+httpSendRequest(HttpStateData * httpState)
+{
+ MemBuf mb;
+ request_t *req = httpState->request;
+ StoreEntry *entry = httpState->entry;
+ peer *p = httpState->peer;
+ CWCB *sendHeaderDone;
+ int fd = httpState->fd;
+
+ debug(11, 5) ("httpSendRequest: FD %d: httpState %p.\n", fd, httpState);
+
+ /* Schedule read reply. (but no timeout set until request fully sent) */
+ commSetTimeout(fd, Config.Timeout.lifetime, httpTimeout, httpState);
+ commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
+
+ if (httpState->orig_request->body_reader)
+ sendHeaderDone = httpSendRequestEntry;
+ else
+ sendHeaderDone = httpSendComplete;
+
+ if (p != NULL) {
+ if (p->options.originserver)
+ httpState->flags.originpeer = 1;
+ else
+ httpState->flags.proxying = 1;
+ } else {
+ httpState->flags.proxying = 0;
+ httpState->flags.originpeer = 0;
+ }
+ /*
+ * Is keep-alive okay for all request methods?
+ */
+ if (!Config.onoff.server_pconns)
+ httpState->flags.keepalive = 0;
+ else if (p == NULL)
+ httpState->flags.keepalive = 1;
+ else if (p->stats.n_keepalives_sent < 10)
+ httpState->flags.keepalive = 1;
+ else if ((double) p->stats.n_keepalives_recv / (double) p->stats.n_keepalives_sent > 0.50)
+ httpState->flags.keepalive = 1;
+ if (httpState->peer) {
+ if (neighborType(httpState->peer, httpState->request) == PEER_SIBLING &&
+ !httpState->peer->options.allow_miss)
+ httpState->flags.only_if_cached = 1;
+ httpState->flags.front_end_https = httpState->peer->front_end_https;
+ }
+ memBufDefInit(&mb);
+ httpBuildRequestPrefix(req,
+ httpState->orig_request,
+ entry,
+ &mb,
+ httpState->flags);
+ if (req->flags.pinned)
+ httpState->flags.keepalive = 1;
+ debug(11, 6) ("httpSendRequest: FD %d:\n%s\n", fd, mb.buf);
+ comm_write_mbuf(fd, mb, sendHeaderDone, httpState);
+}
+
+void
+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],
+ storeUrl(fwd->entry));
+ httpState = cbdataAlloc(HttpStateData);
+ storeLockObject(fwd->entry);
+ httpState->fwd = fwd;
+ httpState->entry = fwd->entry;
+ httpState->fd = fd;
+ if (fwd->servers)
+ httpState->peer = fwd->servers->peer; /* might be NULL */
+ if (httpState->peer) {
+ const char *url;
+ if (httpState->peer->options.originserver)
+ url = strBuf(orig_req->urlpath);
+ else
+ url = storeUrl(httpState->entry);
+ proxy_req = requestCreate(orig_req->method,
+ orig_req->protocol, url);
+ xstrncpy(proxy_req->host, httpState->peer->host, SQUIDHOSTNAMELEN);
+ proxy_req->port = httpState->peer->http_port;
+ proxy_req->flags = orig_req->flags;
+ proxy_req->lastmod = orig_req->lastmod;
+ httpState->request = requestLink(proxy_req);
+ httpState->orig_request = requestLink(orig_req);
+ proxy_req->flags.proxying = 1;
+ /*
+ * This NEIGHBOR_PROXY_ONLY check probably shouldn't be here.
+ * We might end up getting the object from somewhere else if,
+ * for example, the request to this neighbor fails.
+ */
+ if (httpState->peer->options.proxy_only)
+ storeReleaseRequest(httpState->entry);
+#if DELAY_POOLS
+ assert(delayIsNoDelay(fd) == 0);
+ if (httpState->peer->options.no_delay)
+ delaySetNoDelay(fd);
+#endif
+ } else {
+ 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.
+ * Now its set in httpSendComplete() after the full request,
+ * including request body, has been written to the server.
+ */
+}
+
+static void
+httpSendRequestEntryDone(int fd, void *data)
+{
+ HttpStateData *httpState = data;
+ aclCheck_t ch;
+ debug(11, 5) ("httpSendRequestEntryDone: FD %d\n",
+ fd);
+ memset(&ch, '\0', sizeof(ch));
+ ch.request = httpState->request;
+ if (!Config.accessList.brokenPosts) {
+ debug(11, 5) ("httpSendRequestEntryDone: No brokenPosts list\n");
+ httpSendComplete(fd, NULL, 0, 0, data);
+ } else if (!aclCheckFast(Config.accessList.brokenPosts, &ch)) {
+ debug(11, 5) ("httpSendRequestEntryDone: didn't match brokenPosts\n");
+ httpSendComplete(fd, NULL, 0, 0, data);
+ } else {
+ debug(11, 2) ("httpSendRequestEntryDone: matched brokenPosts\n");
+ comm_write(fd, "\r\n", 2, httpSendComplete, data, NULL);
+ }
+}
+
+static void
+httpRequestBodyHandler2(void *data)
+{
+ HttpStateData *httpState = (HttpStateData *) data;
+ char *buf = httpState->body_buf;
+ httpState->body_buf = NULL;
+ comm_write(httpState->fd, buf, httpState->body_buf_sz, httpSendRequestEntry, data, memFree8K);
+}
+
+static void
+httpRequestBodyHandler(char *buf, ssize_t size, void *data)
+{
+ HttpStateData *httpState = (HttpStateData *) data;
+ httpState->body_buf = NULL;
+ if (size > 0) {
+ if (httpState->reply_hdr_state >= 2 && !httpState->flags.abuse_detected) {
+ httpState->flags.abuse_detected = 1;
+ debug(11, 1) ("httpSendRequestEntryDone: Likely proxy abuse detected '%s' -> '%s'\n",
+ inet_ntoa(httpState->orig_request->client_addr),
+ storeUrl(httpState->entry));
+ if (httpState->entry->mem_obj->reply->sline.status == HTTP_INVALID_HEADER) {
+ memFree8K(buf);
+ comm_close(httpState->fd);
+ return;
+ }
+ httpState->body_buf = buf;
+ httpState->body_buf_sz = size;
+ /* Give response some time to propagate before sending rest
+ * of request in case of error */
+ eventAdd("POST delay on response", httpRequestBodyHandler2, httpState, 2.0, 1);
+ return;
+ }
+ comm_write(httpState->fd, buf, size, httpSendRequestEntry, data, memFree8K);
+ } else if (size == 0) {
+ /* End of body */
+ memFree8K(buf);
+ httpSendRequestEntryDone(httpState->fd, data);
+ } else {
+ /* Failed to get whole body, probably aborted */
+ memFree8K(buf);
+ httpSendComplete(httpState->fd, NULL, 0, COMM_ERR_CLOSING, data);
+ }
+}
+
+static void
+httpSendRequestEntry(int fd, char *bufnotused, size_t size, int errflag, void *data)
+{
+ HttpStateData *httpState = data;
+ StoreEntry *entry = httpState->entry;
+ debug(11, 5) ("httpSendRequestEntry: FD %d: size %d: errflag %d.\n",
+ fd, (int) size, errflag);
+ if (size > 0) {
+ fd_bytes(fd, size, FD_WRITE);
+ kb_incr(&statCounter.server.all.kbytes_out, size);
+ kb_incr(&statCounter.server.http.kbytes_out, size);
+ }
+ if (errflag == COMM_ERR_CLOSING)
+ return;
+ if (errflag) {
+ ErrorState *err;
+ err = errorCon(ERR_WRITE_ERROR, HTTP_BAD_GATEWAY, httpState->fwd->request);
+ err->xerrno = errno;
+ fwdFail(httpState->fwd, err);
+ comm_close(fd);
+ return;
+ }
+ if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
+ comm_close(fd);
+ return;
+ }
+ httpState->body_buf = memAllocate(MEM_8K_BUF);
+ requestReadBody(httpState->orig_request, httpState->body_buf, 8192, httpRequestBodyHandler, httpState);
+}
+
+void
+httpBuildVersion(http_version_t * version, unsigned int major, unsigned int minor)
+{
+ version->major = major;
+ version->minor = minor;
+}
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/d9/4048b6315c88001b16add8656805b17d squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/d9/4048b6315c88001b16add8656805b17d
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/d9/4048b6315c88001b16add8656805b17d 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/d9/4048b6315c88001b16add8656805b17d 2006-12-10 16:10:54.000000000 +0200
@@ -0,0 +1,32 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+# Add inputs and outputs from these tool invocations to the build variables
+C_SRCS += \
+$(ROOT)/fs/ufs/store_dir_ufs.c \
+$(ROOT)/fs/ufs/store_io_ufs.c
+
+OBJS += \
+./fs/ufs/store_dir_ufs.o \
+./fs/ufs/store_io_ufs.o
+
+DEPS += \
+${addprefix ./fs/ufs/, \
+store_dir_ufs.d \
+store_io_ufs.d \
+}
+
+
+# Each subdirectory must supply rules for building sources it contributes
+fs/ufs/%.o: $(ROOT)/fs/ufs/%.c
+ @echo 'Building file: $<'
+ @echo 'Invoking: GCC C Compiler'
+ @echo gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $<
+ @gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $< && \
+ echo -n $(@:%.o=%.d) $(dir $@) > $(@:%.o=%.d) && \
+ gcc -MM -MG -P -w -O0 -g3 -Wall -c -fmessage-length=0 $< >> $(@:%.o=%.d)
+ @echo 'Finished building: $<'
+ @echo ' '
+
+
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/de/9075cf315c88001b16add8656805b17d squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/de/9075cf315c88001b16add8656805b17d
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/de/9075cf315c88001b16add8656805b17d 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/de/9075cf315c88001b16add8656805b17d 2006-12-10 16:10:54.000000000 +0200
@@ -0,0 +1,35 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+# Add inputs and outputs from these tool invocations to the build variables
+C_SRCS += \
+$(ROOT)/fs/coss/async_io.c \
+$(ROOT)/fs/coss/store_dir_coss.c \
+$(ROOT)/fs/coss/store_io_coss.c
+
+OBJS += \
+./fs/coss/async_io.o \
+./fs/coss/store_dir_coss.o \
+./fs/coss/store_io_coss.o
+
+DEPS += \
+${addprefix ./fs/coss/, \
+async_io.d \
+store_dir_coss.d \
+store_io_coss.d \
+}
+
+
+# Each subdirectory must supply rules for building sources it contributes
+fs/coss/%.o: $(ROOT)/fs/coss/%.c
+ @echo 'Building file: $<'
+ @echo 'Invoking: GCC C Compiler'
+ @echo gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $<
+ @gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $< && \
+ echo -n $(@:%.o=%.d) $(dir $@) > $(@:%.o=%.d) && \
+ gcc -MM -MG -P -w -O0 -g3 -Wall -c -fmessage-length=0 $< >> $(@:%.o=%.d)
+ @echo 'Finished building: $<'
+ @echo ' '
+
+
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/e7/d04236315c88001b16add8656805b17d squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/e7/d04236315c88001b16add8656805b17d
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/e7/d04236315c88001b16add8656805b17d 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/e7/d04236315c88001b16add8656805b17d 2006-12-10 16:09:19.000000000 +0200
@@ -0,0 +1,988 @@
+
+/*
+ * $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;
+StoreEntry *clientCreateStoreEntry(clientHttpRequest *, method_t, request_flags);
+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, 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, 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, icap->request);
+ err->xerrno = xerrno;
+ 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->chunk_size < 0 )
+ 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) {
+ 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);
+}
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/ee/101d80315c88001b16add8656805b17d squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/ee/101d80315c88001b16add8656805b17d
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/ee/101d80315c88001b16add8656805b17d 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/ee/101d80315c88001b16add8656805b17d 2006-12-10 16:10:53.000000000 +0200
@@ -0,0 +1,28 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+C_SRCS :=
+O_SRCS :=
+ASM_SRCS :=
+S_SRCS :=
+OBJ_SRCS :=
+OBJS :=
+DEPS :=
+EXECUTABLES :=
+
+# Every subdirectory with source files must be described here
+SUBDIRS := \
+. \
+repl/lru \
+repl/heap \
+fs/ufs \
+fs/null \
+fs/diskd \
+fs/coss \
+fs/aufs \
+auth/ntlm \
+auth/negotiate \
+auth/digest \
+auth/basic \
+
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/f0/80118ad06788001b16add8656805b17d squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/f0/80118ad06788001b16add8656805b17d
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/f0/80118ad06788001b16add8656805b17d 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/f0/80118ad06788001b16add8656805b17d 2006-12-10 16:09:19.000000000 +0200
@@ -0,0 +1,2655 @@
+
+/*
+ * $Id: structs.h,v 1.504 2006/10/23 11:22:21 hno Exp $
+ *
+ *
+ * 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.
+ *
+ */
+
+#ifndef SQUID_STRUCTS_H
+#define SQUID_STRUCTS_H
+
+#include "config.h"
+#include "splay.h"
+
+struct _dlink_node {
+ void *data;
+ dlink_node *prev;
+ dlink_node *next;
+};
+
+struct _dlink_list {
+ dlink_node *head;
+ dlink_node *tail;
+};
+
+#if USE_SSL
+struct _acl_cert_data {
+ splayNode *values;
+ char *attribute;
+};
+
+#endif
+
+struct _acl_user_data {
+ splayNode *names;
+ struct {
+ unsigned int case_insensitive:1;
+ unsigned int required:1;
+ } flags;
+};
+
+struct _acl_user_ip_data {
+ int max;
+ struct {
+ unsigned int strict:1;
+ } flags;
+};
+
+struct _acl_ip_data {
+ struct in_addr addr1; /* if addr2 non-zero then its a range */
+ struct in_addr addr2;
+ struct in_addr mask;
+ acl_ip_data *next; /* used for parsing, not for storing */
+};
+
+struct _acl_time_data {
+ int weekbits;
+ int start;
+ int stop;
+ acl_time_data *next;
+};
+
+struct _acl_name_list {
+ char name[ACL_NAME_SZ];
+ acl_name_list *next;
+};
+
+struct _acl_proxy_auth_match_cache {
+ dlink_node link;
+ int matchrv;
+ void *acl_data;
+};
+
+struct _acl_hdr_data {
+ acl_hdr_data *next;
+ relist *reglist;
+ http_hdr_type hdr_id;
+ const char *hdr_name;
+};
+
+struct _auth_user_hash_pointer {
+ /* first two items must be same as hash_link */
+ char *key;
+ auth_user_hash_pointer *next;
+ auth_user_t *auth_user;
+ dlink_node link; /* other hash entries that point to the same auth_user */
+};
+
+struct _auth_user_ip_t {
+ dlink_node node;
+ /* IP addr this user authenticated from */
+ struct in_addr ipaddr;
+ time_t ip_expiretime;
+};
+
+struct _auth_user_t {
+ /* extra fields for proxy_auth */
+ /* this determines what scheme owns the user data. */
+ auth_type_t auth_type;
+ /* the index +1 in the authscheme_list to the authscheme entry */
+ int auth_module;
+ /* we only have one username associated with a given auth_user struct */
+ auth_user_hash_pointer *usernamehash;
+ /* cache of acl lookups on this username */
+ dlink_list proxy_match_cache;
+ /* what ip addresses has this user been seen at?, plus a list length cache */
+ dlink_list ip_list;
+ int ipcount;
+ long expiretime;
+ /* how many references are outstanding to this instance */
+ int references;
+ /* the auth scheme has it's own private data area */
+ void *scheme_data;
+ /* the auth_user_request structures that link to this. Yes it could be a splaytree
+ * but how many requests will a single username have in parallel? */
+ dlink_list requests;
+};
+
+struct _auth_user_request_t {
+ /* this is the object passed around by client_side and acl functions */
+ /* it has request specific data, and links to user specific data */
+ /* the user */
+ auth_user_t *auth_user;
+ /* return a message on the 407 error pages */
+ char *message;
+ /* any scheme specific request related data */
+ void *scheme_data;
+ /* how many 'processes' are working on this data */
+ int references;
+ /* We only attempt authentication once per http request. This
+ * is to allow multiple auth acl references from different _access areas
+ * when using connection based authentication
+ */
+ auth_acl_t lastReply;
+};
+
+
+/*
+ * This defines an auth scheme module
+ */
+
+struct _authscheme_entry {
+ const char *typestr;
+ AUTHSACTIVE *Active;
+ AUTHSADDHEADER *AddHeader;
+ AUTHSADDTRAILER *AddTrailer;
+ AUTHSAUTHED *authenticated;
+ AUTHSAUTHUSER *authAuthenticate;
+ AUTHSCONFIGURED *configured;
+ AUTHSDUMP *dump;
+ AUTHSFIXERR *authFixHeader;
+ AUTHSFREE *FreeUser;
+ AUTHSFREECONFIG *freeconfig;
+ AUTHSUSERNAME *authUserUsername;
+ AUTHSONCLOSEC *oncloseconnection; /*optional */
+ AUTHSCONNLASTHEADER *authConnLastHeader;
+ AUTHSDECODE *decodeauth;
+ AUTHSDIRECTION *getdirection;
+ AUTHSPARSE *parse;
+ AUTHSCHECKCONFIG *checkconfig;
+ AUTHSINIT *init;
+ AUTHSREQFREE *requestFree;
+ AUTHSSHUTDOWN *donefunc;
+ AUTHSSTART *authStart;
+ AUTHSSTATS *authStats;
+};
+
+/*
+ * This is a configured auth scheme
+ */
+
+/* private data types */
+struct _authScheme {
+ /* pointer to the authscheme_list's string entry */
+ const char *typestr;
+ /* the scheme id in the authscheme_list */
+ int Id;
+ /* the scheme's configuration details. */
+ void *scheme_data;
+};
+
+struct _acl_deny_info_list {
+ int err_page_id;
+ char *err_page_name;
+ acl_name_list *acl_list;
+ acl_deny_info_list *next;
+};
+
+#if USE_ARP_ACL
+
+struct _acl_arp_data {
+ char eth[6];
+};
+
+#endif
+
+struct _String {
+ /* never reference these directly! */
+ unsigned short int size; /* buffer size; 64K limit */
+ unsigned short int len; /* current length */
+ char *buf;
+};
+
+struct _header_mangler {
+ acl_access *access_list;
+ char *replacement;
+ /* What follows is only used by HDR_OTHER to build a list of named headers */
+ char *name;
+ header_mangler *next;
+};
+
+struct _body_size {
+ dlink_node node;
+ acl_access *access_list;
+ squid_off_t maxsize;
+};
+
+struct _http_version_t {
+ unsigned int major;
+ unsigned int minor;
+};
+
+#if SQUID_SNMP
+
+struct _snmp_request_t {
+ u_char *buf;
+ u_char *outbuf;
+ int len;
+ int sock;
+ long reqid;
+ int outlen;
+ struct sockaddr_in from;
+ struct snmp_pdu *PDU;
+ aclCheck_t *acl_checklist;
+ u_char *community;
+ struct snmp_session session;
+};
+
+#endif
+
+struct _acl {
+ char name[ACL_NAME_SZ];
+ squid_acl type;
+ void *data;
+ char *cfgline;
+ acl *next;
+};
+
+struct _acl_list {
+ int op;
+ acl *acl;
+ acl_list *next;
+};
+
+struct _acl_access {
+ int allow;
+ acl_list *acl_list;
+ char *cfgline;
+ acl_access *next;
+};
+
+struct _acl_address {
+ acl_address *next;
+ acl_list *acl_list;
+ struct in_addr addr;
+};
+
+struct _acl_tos {
+ acl_tos *next;
+ acl_list *acl_list;
+ int tos;
+};
+
+struct _aclCheck_t {
+ const acl_access *access_list;
+ struct in_addr src_addr;
+ struct in_addr dst_addr;
+ struct in_addr my_addr;
+ unsigned short my_port;
+ request_t *request;
+ /* for acls that look at reply data */
+ HttpReply *reply;
+ ConnStateData *conn; /* hack for ident and NTLM */
+ char rfc931[USER_IDENT_SZ];
+ auth_user_request_t *auth_user_request;
+ acl_lookup_state state[ACL_ENUM_MAX];
+#if SQUID_SNMP
+ char *snmp_community;
+#endif
+ PF *callback;
+ void *callback_data;
+ external_acl_entry *extacl_entry;
+ acl *current_acl; /* private, used by aclCheck */
+};
+
+struct _wordlist {
+ char *key;
+ wordlist *next;
+};
+
+struct _intlist {
+ int i;
+ intlist *next;
+};
+
+struct _intrange {
+ int i;
+ int j;
+ intrange *next;
+};
+
+struct _ushortlist {
+ u_short i;
+ ushortlist *next;
+};
+
+struct _relist {
+ char *pattern;
+ regex_t regex;
+ relist *next;
+};
+
+struct _acl_request_type {
+ unsigned int accelerated:1;
+ unsigned int transparent:1;
+ unsigned int internal:1;
+};
+
+struct _sockaddr_in_list {
+ struct sockaddr_in s;
+ sockaddr_in_list *next;
+};
+
+struct _http_port_list {
+ http_port_list *next;
+ struct sockaddr_in s;
+ char *protocol; /* protocol name */
+ char *name; /* visible name */
+ char *defaultsite; /* default web site */
+ char *urlgroup; /* default urlgroup */
+ unsigned int transparent; /* transparent proxy */
+ unsigned int accel; /* HTTP accelerator */
+ unsigned int vhost; /* uses host header */
+ unsigned int vport; /* virtual port support */
+ unsigned int no_connection_auth; /* Don't support connection oriented auth */
+#if LINUX_TPROXY
+ unsigned int tproxy;
+#endif
+};
+
+#if USE_SSL
+struct _https_port_list {
+ http_port_list http; /* must be first */
+ char *cert;
+ char *key;
+ int version;
+ char *cipher;
+ char *options;
+ char *clientca;
+ char *cafile;
+ char *capath;
+ char *crlfile;
+ char *dhfile;
+ char *sslflags;
+ char *sslcontext;
+ SSL_CTX *sslContext;
+};
+
+#endif
+
+#if DELAY_POOLS
+struct _delaySpec {
+ int restore_bps;
+ int max_bytes;
+};
+
+/* malloc()'d only as far as used (class * sizeof(delaySpec)!
+ * order of elements very important!
+ */
+struct _delaySpecSet {
+ delaySpec aggregate;
+ delaySpec individual;
+ delaySpec network;
+};
+
+struct _delayConfig {
+ unsigned short pools;
+ unsigned short initial;
+ unsigned char *class;
+ delaySpecSet **rates;
+ acl_access **access;
+};
+
+#endif
+
+struct _RemovalPolicySettings {
+ char *type;
+ 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;
+ int highWaterMark;
+ int lowWaterMark;
+ } Swap;
+ squid_off_t memMaxSize;
+ struct {
+ char *relayHost;
+ u_short relayPort;
+ peer *peer;
+ } Wais;
+ struct {
+ squid_off_t min;
+ int pct;
+ squid_off_t max;
+ } quickAbort;
+ squid_off_t readAheadGap;
+ RemovalPolicySettings *replPolicy;
+ RemovalPolicySettings *memPolicy;
+ time_t negativeTtl;
+ time_t negativeDnsTtl;
+ time_t positiveDnsTtl;
+ time_t shutdownLifetime;
+ struct {
+ time_t read;
+ time_t lifetime;
+ time_t forward;
+ time_t connect;
+ time_t peer_connect;
+ time_t request;
+ time_t persistent_request;
+ time_t pconn;
+ time_t siteSelect;
+ time_t deadPeer;
+ int icp_query; /* msec */
+ int icp_query_max; /* msec */
+ int mcast_icp_query; /* msec */
+#if USE_IDENT
+ time_t ident;
+#endif
+#if !USE_DNSSERVERS
+ time_t idns_retransmit;
+ time_t idns_query;
+#endif
+ } Timeout;
+ squid_off_t maxRequestHeaderSize;
+ squid_off_t maxRequestBodySize;
+ squid_off_t maxReplyHeaderSize;
+ dlink_list ReplyBodySize;
+ struct {
+ u_short icp;
+#if USE_HTCP
+ u_short htcp;
+#endif
+#if SQUID_SNMP
+ u_short snmp;
+#endif
+ } Port;
+ struct {
+ http_port_list *http;
+#if USE_SSL
+ https_port_list *https;
+#endif
+ } Sockaddr;
+#if SQUID_SNMP
+ struct {
+ char *configFile;
+ char *agentInfo;
+ } Snmp;
+#endif
+#if USE_WCCP
+ struct {
+ struct in_addr router;
+ struct in_addr address;
+ int version;
+ } Wccp;
+#endif
+#if USE_WCCPv2
+ struct {
+ sockaddr_in_list *router;
+ struct in_addr address;
+ int forwarding_method;
+ int return_method;
+ int assignment_method;
+ int weight;
+ int rebuildwait;
+ void *info;
+ } Wccp2;
+#endif
+ char *as_whois_server;
+ struct {
+ char *log;
+ char *store;
+ char *swap;
+#if USE_USERAGENT_LOG
+ char *useragent;
+#endif
+#if USE_REFERER_LOG
+ char *referer;
+#endif
+#if WIP_FWD_LOG
+ char *forward;
+#endif
+ logformat *logformats;
+ customlog *accesslogs;
+ int rotateNumber;
+ } Log;
+ char *adminEmail;
+ char *EmailFrom;
+ char *EmailProgram;
+ char *effectiveUser;
+ char *visible_appname_string;
+ char *effectiveGroup;
+ struct {
+#if USE_DNSSERVERS
+ char *dnsserver;
+#endif
+ struct {
+ wordlist *command;
+ int children;
+ int concurrency;
+ } url_rewrite;
+ struct {
+ wordlist *command;
+ int children;
+ int concurrency;
+ } location_rewrite;
+#if USE_ICMP
+ char *pinger;
+#endif
+#if USE_UNLINKD
+ char *unlinkd;
+#endif
+ char *diskd;
+#if USE_SSL
+ char *ssl_password;
+#endif
+ } Program;
+#if USE_DNSSERVERS
+ int dnsChildren;
+#endif
+ time_t authenticateGCInterval;
+ time_t authenticateTTL;
+ time_t authenticateIpTTL;
+ char *appendDomain;
+ int appendDomainLen;
+ char *debugOptions;
+ char *pidFilename;
+ char *mimeTablePathname;
+ char *etcHostsPath;
+ char *visibleHostname;
+ char *uniqueHostname;
+ wordlist *hostnameAliases;
+ char *errHtmlText;
+ struct {
+ char *host;
+ char *file;
+ time_t period;
+ u_short port;
+ } Announce;
+ struct {
+ struct in_addr udp_incoming;
+ struct in_addr udp_outgoing;
+#if SQUID_SNMP
+ struct in_addr snmp_incoming;
+ struct in_addr snmp_outgoing;
+#endif
+ struct in_addr client_netmask;
+ } Addrs;
+ squid_off_t tcpRcvBufsz;
+ squid_off_t udpMaxHitObjsz;
+ wordlist *hierarchy_stoplist;
+ wordlist *mcast_group_list;
+ wordlist *dns_testname_list;
+ wordlist *dns_nameservers;
+ peer *peers;
+ int npeers;
+ struct {
+ int size;
+ int low;
+ int high;
+ } ipcache;
+ struct {
+ int size;
+ } fqdncache;
+ int minDirectHops;
+ int minDirectRtt;
+ cachemgr_passwd *passwd_list;
+ struct {
+ int objectsPerBucket;
+ squid_off_t avgObjectSize;
+ squid_off_t maxObjectSize;
+ squid_off_t minObjectSize;
+ squid_off_t maxInMemObjSize;
+ } Store;
+ struct {
+ int high;
+ int low;
+ time_t period;
+ } Netdb;
+ struct {
+ int log_udp;
+ int res_defnames;
+ int anonymizer;
+ int client_db;
+ int query_icmp;
+ int icp_hit_stale;
+ int buffered_logs;
+#if ALLOW_SOURCE_PING
+ int source_ping;
+#endif
+ int common_log;
+ int log_mime_hdrs;
+ int log_fqdn;
+ int announce;
+ int mem_pools;
+ int test_reachability;
+ int half_closed_clients;
+#if HTTP_VIOLATIONS
+ int reload_into_ims;
+#endif
+ int offline;
+ int redir_rewrites_host;
+ int prefer_direct;
+ int nonhierarchical_direct;
+ int strip_query_terms;
+ int redirector_bypass;
+ int ignore_unknown_nameservers;
+ int client_pconns;
+ int server_pconns;
+ int error_pconns;
+#if USE_CACHE_DIGESTS
+ int digest_generation;
+#endif
+ int log_ip_on_direct;
+ int ie_refresh;
+ int vary_ignore_expire;
+ int pipeline_prefetch;
+ int request_entities;
+ int detect_broken_server_pconns;
+ int balance_on_multiple_ip;
+ int collapsed_forwarding;
+ int relaxed_header_parser;
+ int accel_no_pmtu_disc;
+ int global_internal_static;
+ int httpd_suppress_version_string;
+ int via;
+ int check_hostnames;
+ int allow_underscore;
+ int cache_vary;
+#if FOLLOW_X_FORWARDED_FOR
+ int acl_uses_indirect_client;
+ int delay_pool_uses_indirect_client;
+ int log_uses_indirect_client;
+#endif
+ } onoff;
+ acl *aclList;
+ struct {
+ acl_access *http;
+ acl_access *http2;
+ acl_access *icp;
+ acl_access *miss;
+ acl_access *NeverDirect;
+ acl_access *AlwaysDirect;
+ acl_access *ASlists;
+ acl_access *noCache;
+ acl_access *log;
+#if SQUID_SNMP
+ acl_access *snmp;
+#endif
+ acl_access *brokenPosts;
+#if USE_IDENT
+ acl_access *identLookup;
+#endif
+ acl_access *url_rewrite;
+ acl_access *location_rewrite;
+ acl_access *reply;
+ acl_address *outgoing_address;
+ acl_tos *outgoing_tos;
+#if USE_HTCP
+ acl_access *htcp;
+ acl_access *htcp_clr;
+#endif
+#if FOLLOW_X_FORWARDED_FOR
+ acl_access *followXFF;
+#endif
+ acl_access *vary_encoding;
+ } accessList;
+ acl_deny_info_list *denyInfoList;
+ struct _authConfig {
+ authScheme *schemes;
+ int n_allocated;
+ int n_configured;
+ } authConfig;
+ struct {
+ int list_width;
+ int list_wrap;
+ char *anon_user;
+ int passive;
+ int sanitycheck;
+ int telnet;
+ } Ftp;
+ refresh_t *Refresh;
+ struct _cacheSwap {
+ SwapDir *swapDirs;
+ int n_allocated;
+ int n_configured;
+ } cacheSwap;
+ struct {
+ char *directory;
+ int use_short_names;
+ } icons;
+ char *errorDirectory;
+ struct {
+ int maxtries;
+ int onerror;
+ } retry;
+ struct {
+ squid_off_t limit;
+ } MemPools;
+#if DELAY_POOLS
+ delayConfig Delay;
+#endif
+ struct {
+ int icp_average;
+ int dns_average;
+ int http_average;
+ int icp_min_poll;
+ int dns_min_poll;
+ int http_min_poll;
+ } comm_incoming;
+ int max_open_disk_fds;
+ int uri_whitespace;
+ squid_off_t rangeOffsetLimit;
+#if MULTICAST_MISS_STREAM
+ struct {
+ struct in_addr addr;
+ int ttl;
+ unsigned short port;
+ char *encode_key;
+ } mcast_miss;
+#endif
+ header_mangler header_access[HDR_ENUM_END];
+ char *coredump_dir;
+ char *chroot_dir;
+#if USE_CACHE_DIGESTS
+ struct {
+ int bits_per_entry;
+ time_t rebuild_period;
+ time_t rewrite_period;
+ squid_off_t swapout_chunk_size;
+ int rebuild_chunk_percentage;
+ } digest;
+#endif
+#if USE_SSL
+ struct {
+ int unclean_shutdown;
+ char *ssl_engine;
+ } SSL;
+#endif
+ struct {
+ int high_rptm;
+ int high_pf;
+ squid_off_t high_memory;
+ } warnings;
+ char *store_dir_select_algorithm;
+ int sleep_after_fork; /* microseconds */
+ time_t minimum_expiry_time; /* seconds */
+ external_acl *externalAclHelperList;
+ errormap *errorMapList;
+#if USE_SSL
+ struct {
+ char *cert;
+ char *key;
+ int version;
+ char *options;
+ char *cipher;
+ char *cafile;
+ char *capath;
+ char *crlfile;
+ char *flags;
+ SSL_CTX *sslContext;
+ } ssl_client;
+#endif
+ time_t refresh_stale_window;
+ int umask;
+#ifdef HS_FEAT_ICAP
+ IcapConfig icapcfg;
+#endif
+};
+
+struct _SquidConfig2 {
+ struct {
+ int enable_purge;
+ } onoff;
+ uid_t effectiveUserID;
+ gid_t effectiveGroupID;
+};
+
+struct _close_handler {
+ PF *handler;
+ void *data;
+ close_handler *next;
+};
+
+struct _dread_ctrl {
+ int fd;
+ off_t file_offset;
+ size_t req_len;
+ char *buf;
+ int end_of_file;
+ DRCB *handler;
+ void *client_data;
+};
+
+struct _dwrite_q {
+ off_t file_offset;
+ char *buf;
+ size_t len;
+ size_t buf_offset;
+ dwrite_q *next;
+ FREE *free_func;
+};
+
+struct _CommWriteStateData {
+ int valid;
+ char *buf;
+ size_t size;
+ size_t offset;
+ CWCB *handler;
+ void *handler_data;
+ FREE *free_func;
+};
+
+
+/* ETag support is rudimantal;
+ * this struct is likely to change
+ * Note: "str" points to memory in HttpHeaderEntry (for now)
+ * so ETags should be used as tmp variables only (for now) */
+struct _ETag {
+ const char *str; /* quoted-string */
+ int weak; /* true if it is a weak validator */
+};
+
+struct _fde {
+ unsigned int type;
+ u_short local_port;
+ u_short remote_port;
+ struct in_addr local_addr;
+ unsigned char tos;
+ char ipaddr[16]; /* dotted decimal address of peer */
+ char desc[FD_DESC_SZ];
+ struct {
+ unsigned int open:1;
+ unsigned int close_request:1;
+ unsigned int write_daemon:1;
+ unsigned int closing:1;
+ unsigned int socket_eof:1;
+ unsigned int nolinger:1;
+ unsigned int nonblocking:1;
+ unsigned int ipc:1;
+ unsigned int called_connect:1;
+ unsigned int nodelay:1;
+ unsigned int close_on_exec:1;
+ unsigned int backoff:1; /* keep track of whether the fd is backed off */
+ } flags;
+ comm_pending read_pending;
+ 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;
+ void *wrt_handle_data;
+ dwrite_q *write_q;
+ dwrite_q *write_q_tail;
+ off_t offset;
+ } disk;
+ PF *read_handler;
+ void *read_data;
+ PF *write_handler;
+ void *write_data;
+ PF *timeout_handler;
+ time_t timeout;
+ void *timeout_data;
+ void *lifetime_data;
+ close_handler *close_handler; /* linked list */
+ DEFER *defer_check; /* check if we should defer read */
+ void *defer_data;
+ struct _CommWriteStateData rwstate; /* State data for comm_write */
+ READ_HANDLER *read_method;
+ WRITE_HANDLER *write_method;
+#if USE_SSL
+ SSL *ssl;
+#endif
+#ifdef _SQUID_MSWIN_
+ struct {
+ long handle;
+ } win32;
+#endif
+#if DELAY_POOLS
+ int slow_id;
+#endif
+};
+
+struct _fileMap {
+ int max_n_files;
+ int n_files_in_map;
+ int toggle;
+ int nwords;
+ unsigned long *file_map;
+};
+
+/* auto-growing memory-resident buffer with printf interface */
+/* note: when updating this struct, update MemBufNULL #define */
+struct _MemBuf {
+ /* public, read-only */
+ char *buf;
+ mb_size_t size; /* used space, does not count 0-terminator */
+
+ /* private, stay away; use interface function instead */
+ mb_size_t max_capacity; /* when grows: assert(new_capacity <= max_capacity) */
+ mb_size_t capacity; /* allocated space */
+ unsigned stolen:1; /* the buffer has been stolen for use by someone else */
+};
+
+/* see Packer.c for description */
+struct _Packer {
+ /* protected, use interface functions instead */
+ append_f append;
+ vprintf_f packer_vprintf;
+ void *real_handle; /* first parameter to real append and vprintf */
+};
+
+/* http status line */
+struct _HttpStatusLine {
+ /* public, read only */
+ http_version_t version;
+ const char *reason; /* points to a _constant_ string (default or supplied), never free()d */
+ http_status status;
+};
+
+/*
+ * Note: HttpBody is used only for messages with a small content that is
+ * known a priory (e.g., error messages).
+ */
+struct _HttpBody {
+ /* private */
+ MemBuf mb;
+};
+
+/* http header extention field */
+struct _HttpHdrExtField {
+ String name; /* field-name from HTTP/1.1 (no column after name) */
+ String value; /* field-value from HTTP/1.1 */
+};
+
+/* http cache control header field */
+struct _HttpHdrCc {
+ int mask;
+ int max_age;
+ int s_maxage;
+ int max_stale;
+ String other;
+};
+
+/* http byte-range-spec */
+struct _HttpHdrRangeSpec {
+ squid_off_t offset;
+ squid_off_t length;
+};
+
+/* There may be more than one byte range specified in the request.
+ * This object holds all range specs in order of their appearence
+ * in the request because we SHOULD preserve that order.
+ */
+struct _HttpHdrRange {
+ Stack specs;
+};
+
+/* http content-range header field */
+struct _HttpHdrContRange {
+ HttpHdrRangeSpec spec;
+ squid_off_t elength; /* entity length, not content length */
+};
+
+/* some fields can hold either time or etag specs (e.g. If-Range) */
+struct _TimeOrTag {
+ const char *tag; /* entity tag */
+ time_t time;
+ int valid; /* true if struct is usable */
+};
+
+/* data for iterating thru range specs */
+struct _HttpHdrRangeIter {
+ HttpHdrRangePos pos;
+ const HttpHdrRangeSpec *spec; /* current spec at pos */
+ squid_off_t debt_size; /* bytes left to send from the current spec */
+ squid_off_t prefix_size; /* the size of the incoming HTTP msg prefix */
+ String boundary; /* boundary for multipart responses */
+};
+
+/* constant attributes of http header fields */
+struct _HttpHeaderFieldAttrs {
+ const char *name;
+ http_hdr_type id;
+ field_type type;
+};
+
+/* per field statistics */
+struct _HttpHeaderFieldStat {
+ int aliveCount; /* created but not destroyed (count) */
+ int seenCount; /* #fields we've seen */
+ int parsCount; /* #parsing attempts */
+ int errCount; /* #pasring errors */
+ int repCount; /* #repetitons */
+};
+
+/* compiled version of HttpHeaderFieldAttrs plus stats */
+struct _HttpHeaderFieldInfo {
+ http_hdr_type id;
+ String name;
+ field_type type;
+ HttpHeaderFieldStat stat;
+};
+
+struct _HttpHeaderEntry {
+ http_hdr_type id;
+ String name;
+ String value;
+};
+
+struct _HttpHeader {
+ /* protected, do not use these, use interface functions instead */
+ Array entries; /* parsed fields in raw format */
+ HttpHeaderMask mask; /* bit set <=> entry present */
+ http_hdr_owner_type owner; /* request or reply */
+ int len; /* length when packed, not counting terminating '\0' */
+};
+
+struct _HttpReply {
+ /* unsupported, writable, may disappear/change in the future */
+ int hdr_sz; /* sums _stored_ status-line, headers, and */
+
+ /* public, readable; never update these or their .hdr equivalents directly */
+ squid_off_t content_length;
+ time_t date;
+ time_t last_modified;
+ time_t expires;
+ String content_type;
+ HttpHdrCc *cache_control;
+ HttpHdrContRange *content_range;
+ short int keep_alive;
+
+ /* public, readable */
+ HttpMsgParseState pstate; /* the current parsing state */
+
+ /* public, writable, but use httpReply* interfaces when possible */
+ HttpStatusLine sline;
+ HttpHeader header;
+ HttpBody body; /* for small constant memory-resident text bodies only */
+};
+
+struct _http_state_flags {
+ unsigned int proxying:1;
+ unsigned int keepalive:1;
+ unsigned int only_if_cached:1;
+ unsigned int keepalive_broken:1;
+ unsigned int abuse_detected:1;
+ unsigned int request_sent:1;
+ unsigned int front_end_https:2;
+ 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;
+ MemBuf reply_hdr;
+ int reply_hdr_state;
+ peer *peer; /* peer request made to */
+ int eof; /* reached end-of-object? */
+ request_t *orig_request;
+ 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;
+ size_t len;
+ icpUdpData *next;
+#ifndef LESS_TIMING
+ struct timeval start;
+#endif
+ log_type logcode;
+ struct timeval queue_time;
+};
+
+struct _ping_data {
+ struct timeval start;
+ struct timeval stop;
+ int n_sent;
+ int n_recv;
+ int n_replies_expected;
+ int timeout; /* msec */
+ int timedout;
+ int w_rtt;
+ int p_rtt;
+};
+
+struct _HierarchyLogEntry {
+ hier_code code;
+ char host[SQUIDHOSTNAMELEN];
+ ping_data ping;
+ char cd_host[SQUIDHOSTNAMELEN]; /* the host of selected by cd peer */
+ lookup_t cd_lookup; /* cd prediction: none, miss, hit */
+ int n_choices; /* #peers we selected from (cd only) */
+ int n_ichoices; /* #peers with known rtt we selected from (cd only) */
+ struct timeval peer_select_start;
+ struct timeval store_complete_stop;
+};
+
+struct _AccessLogEntry {
+ const char *url;
+ struct {
+ method_t method;
+ int code;
+ const char *content_type;
+ http_version_t version;
+ } http;
+ struct {
+ icp_opcode opcode;
+ } icp;
+ struct {
+ struct in_addr caddr;
+ squid_off_t size;
+ log_type code;
+ int msec;
+ const char *rfc931;
+ const char *authuser;
+#if USE_SSL
+ const char *ssluser;
+#endif
+ } cache;
+ struct {
+ char *request;
+ char *reply;
+ } headers;
+ struct {
+ const char *method_str;
+ } private;
+ HierarchyLogEntry hier;
+ HttpReply *reply;
+ request_t *request;
+};
+
+struct _clientHttpRequest {
+ ConnStateData *conn;
+ request_t *request; /* Parsed URL ... */
+ request_t *orig_request; /* Parsed URL ... */
+ store_client *sc; /* The store_client we're using */
+ store_client *old_sc; /* ... for entry to be validated */
+ char *uri;
+ char *log_uri;
+ struct {
+ squid_off_t offset;
+ squid_off_t size;
+ } out;
+ HttpReply *reply; /* it is important for clientHttpRequest
+ * to have its own HttpReply for
+ * logging, especially in cases
+ * where the reply headers sent to
+ * the client are different than
+ * those received from the origin server. */
+ HttpHdrRangeIter range_iter; /* data for iterating thru range specs */
+ size_t req_sz; /* raw request size on input, not current request size */
+ StoreEntry *entry;
+ StoreEntry *old_entry;
+ log_type log_type;
+#if USE_CACHE_DIGESTS
+ const char *lookup_type; /* temporary hack: storeGet() result: HIT/MISS/NONE */
+#endif
+ struct timeval start;
+ http_version_t http_ver;
+ int redirect_state;
+ aclCheck_t *acl_checklist; /* need ptr back so we can unreg if needed */
+ clientHttpRequest *next;
+ AccessLogEntry al;
+ struct {
+ unsigned int accel:1;
+ unsigned int transparent:1;
+ 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 {
+ http_status status;
+ char *location;
+ } redirect;
+ dlink_node active;
+ squid_off_t maxBodySize;
+#if HS_FEAT_ICAP
+ IcapStateData *icap_reqmod;
+#endif
+};
+
+struct _ConnStateData {
+ int fd;
+ struct {
+ char *buf;
+ size_t offset;
+ size_t size;
+ } in;
+ struct {
+ squid_off_t size_left; /* How much body left to process */
+ request_t *request; /* Parameters passed to clientReadBody */
+ char *buf;
+ size_t bufsize;
+ CBCB *callback;
+ void *cbdata;
+ } body;
+ auth_type_t auth_type; /* Is this connection based authentication ? if so
+ * what type it is. */
+ /* note this is ONLY connection based because NTLM is against HTTP spec */
+ /* the user details for connection based authentication */
+ auth_user_request_t *auth_user_request;
+ clientHttpRequest *chr;
+ struct sockaddr_in peer;
+ struct sockaddr_in me;
+ struct in_addr log_addr;
+ char rfc931[USER_IDENT_SZ];
+ int nrequests;
+ struct {
+ int n;
+ time_t until;
+ } defer;
+ http_port_list *port;
+ int transparent;
+ struct {
+ int fd; /* pinned server side connection */
+ char *host; /* host name of pinned connection */
+ int port; /* port of pinned connection */
+ int pinned; /* this connection was pinned */
+ int auth; /* pinned for www authentication */
+ peer *peer; /* peer the connection goes via */
+ } pinning;
+};
+
+struct _ipcache_addrs {
+ struct in_addr *in_addrs;
+ unsigned char *bad_mask;
+ unsigned char count;
+ unsigned char cur;
+ unsigned char badcount;
+};
+
+struct _domain_ping {
+ char *domain;
+ int do_ping; /* boolean */
+ domain_ping *next;
+};
+
+struct _domain_type {
+ char *domain;
+ peer_t type;
+ domain_type *next;
+};
+
+#if USE_CACHE_DIGESTS
+struct _Version {
+ short int current; /* current version */
+ short int required; /* minimal version that can safely handle current version */
+};
+
+/* digest control block; used for transmission and storage */
+struct _StoreDigestCBlock {
+ Version ver;
+ int capacity;
+ int count;
+ int del_count;
+ int mask_size;
+ unsigned char bits_per_entry;
+ unsigned char hash_func_count;
+ short int reserved_short;
+ int reserved[32 - 6];
+};
+
+struct _DigestFetchState {
+ PeerDigest *pd;
+ StoreEntry *entry;
+ StoreEntry *old_entry;
+ store_client *sc;
+ store_client *old_sc;
+ request_t *request;
+ squid_off_t offset;
+ squid_off_t mask_offset;
+ time_t start_time;
+ time_t resp_time;
+ time_t expires;
+ struct {
+ int msg;
+ int bytes;
+ } sent, recv;
+};
+
+/* statistics for cache digests and other hit "predictors" */
+struct _cd_guess_stats {
+ /* public, read-only */
+ int true_hits;
+ int false_hits;
+ int true_misses;
+ int false_misses;
+ int close_hits; /* tmp, remove it later */
+};
+
+struct _PeerDigest {
+ peer *peer; /* pointer back to peer structure, argh */
+ CacheDigest *cd; /* actual digest structure */
+ String host; /* copy of peer->host */
+ const char *req_result; /* text status of the last request */
+ struct {
+ unsigned int needed:1; /* there were requests for this digest */
+ unsigned int usable:1; /* can be used for lookups */
+ unsigned int requested:1; /* in process of receiving [fresh] digest */
+ } flags;
+ struct {
+ /* all times are absolute unless augmented with _delay */
+ time_t initialized; /* creation */
+ time_t needed; /* first lookup/use by a peer */
+ time_t next_check; /* next scheduled check/refresh event */
+ time_t retry_delay; /* delay before re-checking _invalid_ digest */
+ time_t requested; /* requested a fresh copy of a digest */
+ time_t req_delay; /* last request response time */
+ time_t received; /* received the current copy of a digest */
+ time_t disabled; /* disabled for good */
+ } times;
+ struct {
+ cd_guess_stats guess;
+ int used_count;
+ struct {
+ int msgs;
+ kb_t kbytes;
+ } sent, recv;
+ } stats;
+};
+
+#endif
+
+struct _peer {
+ char *name;
+ char *host;
+ peer_t type;
+ struct sockaddr_in in_addr;
+ struct {
+ int pings_sent;
+ int pings_acked;
+ int fetches;
+ int rtt;
+ int ignored_replies;
+ int n_keepalives_sent;
+ int n_keepalives_recv;
+ time_t probe_start;
+ time_t last_query;
+ time_t last_reply;
+ time_t last_connect_failure;
+ time_t last_connect_probe;
+ int logged_state; /* so we can print dead/revived msgs */
+ int conn_open; /* current opened connections */
+ } stats;
+ struct {
+ int version;
+ int counts[ICP_END];
+ u_short port;
+ } icp;
+#if USE_HTCP
+ struct {
+ double version;
+ int counts[2];
+ u_short port;
+ } htcp;
+#endif
+ u_short http_port;
+ domain_ping *peer_domain;
+ domain_type *typelist;
+ acl_access *access;
+ struct {
+ unsigned int proxy_only:1;
+ unsigned int no_query:1;
+ unsigned int no_digest:1;
+ unsigned int default_parent:1;
+ unsigned int roundrobin:1;
+ unsigned int mcast_responder:1;
+ unsigned int closest_only:1;
+#if USE_HTCP
+ unsigned int htcp:1;
+ unsigned int htcp_oldsquid:1;
+#endif
+ unsigned int no_netdb_exchange:1;
+#if DELAY_POOLS
+ unsigned int no_delay:1;
+#endif
+ unsigned int allow_miss:1;
+ unsigned int originserver:1;
+ unsigned int userhash:1;
+ unsigned int sourcehash:1;
+#if USE_CARP
+ unsigned int carp:1;
+#endif
+ } options;
+ int weight;
+ struct {
+ double avg_n_members;
+ int n_times_counted;
+ int n_replies_expected;
+ int ttl;
+ int id;
+ struct {
+ unsigned int count_event_pending:1;
+ unsigned int counting:1;
+ } flags;
+ } mcast;
+#if USE_CACHE_DIGESTS
+ PeerDigest *digest;
+ char *digest_url;
+#endif
+ int tcp_up; /* 0 if a connect() fails */
+ struct in_addr addresses[10];
+ int n_addresses;
+ int rr_count;
+ int rr_lastcount;
+ peer *next;
+ int test_fd;
+#if USE_CARP
+ struct {
+ unsigned int hash;
+ double load_multiplier;
+ double load_factor; /* normalized weight value */
+ } carp;
+#endif
+ struct {
+ unsigned int hash;
+ double load_multiplier;
+ double load_factor;
+ } userhash;
+ struct {
+ unsigned int hash;
+ double load_multiplier;
+ double load_factor;
+ } sourcehash;
+ char *login; /* Proxy authorization */
+ time_t connect_timeout;
+ int max_conn;
+ struct {
+ char *url;
+ int min, max;
+ int interval;
+ int timeout;
+ int state;
+ time_t last;
+ PeerMonitor *data;
+ } monitor;
+ char *domain; /* Forced domain */
+#if USE_SSL
+ int use_ssl;
+ char *sslcert;
+ char *sslkey;
+ int sslversion;
+ char *ssloptions;
+ char *sslcipher;
+ char *sslcafile;
+ char *sslcapath;
+ char *sslcrlfile;
+ char *sslflags;
+ char *ssldomain;
+ SSL_CTX *sslContext;
+ SSL_SESSION *sslSession;
+#endif
+ int front_end_https;
+ int connection_auth;
+};
+
+struct _net_db_name {
+ hash_link hash; /* must be first */
+ net_db_name *next;
+ netdbEntry *net_db_entry;
+};
+
+struct _net_db_peer {
+ const char *peername;
+ double hops;
+ double rtt;
+ time_t expires;
+};
+
+struct _netdbEntry {
+ hash_link hash; /* must be first */
+ char network[16];
+ int pings_sent;
+ int pings_recv;
+ double hops;
+ double rtt;
+ time_t next_ping_time;
+ time_t last_use_time;
+ int link_count;
+ net_db_name *hosts;
+ net_db_peer *peers;
+ int n_peers_alloc;
+ int n_peers;
+};
+
+struct _ps_state {
+ request_t *request;
+ StoreEntry *entry;
+ int always_direct;
+ int never_direct;
+ int direct;
+ PSC *callback;
+ void *callback_data;
+ FwdServer *servers;
+ /*
+ * Why are these struct sockaddr_in instead of peer *? Because a
+ * peer structure can become invalid during the peer selection
+ * phase, specifically after a reconfigure. Thus we need to lookup
+ * the peer * based on the address when we are finally ready to
+ * reference the peer structure.
+ */
+ struct sockaddr_in first_parent_miss;
+ struct sockaddr_in closest_parent_miss;
+ /*
+ * ->hit and ->secho can be peer* because they should only be
+ * accessed during the thread when they are set
+ */
+ peer *hit;
+ peer_t hit_type;
+#if ALLOW_SOURCE_PING
+ peer *secho;
+#endif
+ ping_data ping;
+ aclCheck_t *acl_checklist;
+};
+
+#if USE_ICMP
+struct _pingerEchoData {
+ struct in_addr to;
+ unsigned char opcode;
+ int psize;
+ char payload[PINGER_PAYLOAD_SZ];
+};
+
+struct _pingerReplyData {
+ struct in_addr from;
+ unsigned char opcode;
+ int rtt;
+ int hops;
+ int psize;
+ char payload[PINGER_PAYLOAD_SZ];
+};
+
+#endif
+
+struct _icp_common_t {
+ unsigned char opcode; /* opcode */
+ unsigned char version; /* version number */
+ unsigned short length; /* total length (bytes) */
+ u_num32 reqnum; /* req number (req'd for UDP) */
+ u_num32 flags;
+ u_num32 pad;
+ u_num32 shostid; /* sender host id */
+};
+
+struct _iostats {
+ struct {
+ int reads;
+ int reads_deferred;
+ int read_hist[16];
+ int writes;
+ int write_hist[16];
+ } Http, Ftp, Gopher, Wais;
+};
+
+struct _mem_node {
+ char data[SM_PAGE_SIZE];
+ int len;
+ int uses;
+ mem_node *next;
+};
+
+struct _mem_hdr {
+ mem_node *head;
+ mem_node *tail;
+ squid_off_t origin_offset;
+};
+
+/* keep track each client receiving data from that particular StoreEntry */
+struct _store_client {
+ int type;
+ squid_off_t copy_offset;
+ squid_off_t seen_offset;
+ size_t copy_size;
+ char *copy_buf;
+ STCB *callback;
+ void *callback_data;
+ StoreEntry *entry; /* ptr to the parent StoreEntry, argh! */
+ storeIOState *swapin_sio;
+ struct {
+ unsigned int disk_io_pending:1;
+ unsigned int store_copying:1;
+ unsigned int copy_event_pending:1;
+ } flags;
+#if DELAY_POOLS
+ delay_id delay_id;
+#endif
+ dlink_node node;
+#if STORE_CLIENT_LIST_DEBUG
+ void *owner;
+#endif
+};
+
+
+/* Removal policies */
+
+struct _RemovalPolicyNode {
+ void *data;
+};
+
+struct _RemovalPolicy {
+ const char *_type;
+ void *_data;
+ void (*Free) (RemovalPolicy * policy);
+ void (*Add) (RemovalPolicy * policy, StoreEntry * entry, RemovalPolicyNode * node);
+ void (*Remove) (RemovalPolicy * policy, StoreEntry * entry, RemovalPolicyNode * node);
+ void (*Referenced) (RemovalPolicy * policy, const StoreEntry * entry, RemovalPolicyNode * node);
+ void (*Dereferenced) (RemovalPolicy * policy, const StoreEntry * entry, RemovalPolicyNode * node);
+ RemovalPolicyWalker *(*WalkInit) (RemovalPolicy * policy);
+ RemovalPurgeWalker *(*PurgeInit) (RemovalPolicy * policy, int max_scan);
+ void (*Stats) (RemovalPolicy * policy, StoreEntry * entry);
+};
+
+struct _RemovalPolicyWalker {
+ RemovalPolicy *_policy;
+ void *_data;
+ const StoreEntry *(*Next) (RemovalPolicyWalker * walker);
+ void (*Done) (RemovalPolicyWalker * walker);
+};
+
+struct _RemovalPurgeWalker {
+ RemovalPolicy *_policy;
+ void *_data;
+ int scanned, max_scan, locked;
+ StoreEntry *(*Next) (RemovalPurgeWalker * walker);
+ void (*Done) (RemovalPurgeWalker * walker);
+};
+
+/* This structure can be freed while object is purged out from memory */
+struct _MemObject {
+ method_t method;
+ char *url;
+ mem_hdr data_hdr;
+ squid_off_t inmem_hi;
+ squid_off_t inmem_lo;
+ int serverfd; /* Record the server's fd if we have too much
+ * data waiting to send to the client */
+ dlink_list clients;
+ int nclients;
+ struct {
+ squid_off_t queue_offset; /* relative to in-mem data */
+ mem_node *memnode; /* which node we're currently paging out */
+ storeIOState *sio;
+ } swapout;
+ HttpReply *reply;
+ request_t *request;
+ struct timeval start_ping;
+ IRCB *ping_reply_callback;
+ void *ircb_data;
+ struct {
+ STABH *callback;
+ void *data;
+ } abort;
+ char *log_url;
+ RemovalPolicyNode repl;
+ int id;
+ squid_off_t object_sz;
+ size_t swap_hdr_sz;
+#if URL_CHECKSUM_DEBUG
+ unsigned int chksum;
+#endif
+ const char *vary_hdr;
+ const char *vary_headers;
+ const char *vary_encoding;
+ StoreEntry *ims_entry;
+ time_t refresh_timestamp;
+};
+
+struct _StoreEntry {
+ hash_link hash; /* must be first */
+ MemObject *mem_obj;
+ RemovalPolicyNode repl;
+ /* START OF ON-DISK STORE_META_STD TLV field */
+ time_t timestamp;
+ time_t lastref;
+ time_t expires;
+ time_t lastmod;
+ squid_file_sz swap_file_sz;
+ u_short refcount;
+ u_short flags;
+ /* END OF ON-DISK STORE_META_STD */
+ sfileno swap_filen:25;
+ sdirno swap_dirn:7;
+ u_short lock_count; /* Assume < 65536! */
+ mem_status_t mem_status:3;
+ ping_status_t ping_status:3;
+ store_status_t store_status:3;
+ swap_status_t swap_status:3;
+};
+
+struct _SwapDir {
+ const char *type;
+ int cur_size;
+ int low_size;
+ int max_size;
+ char *path;
+ int index; /* This entry's index into the swapDirs array */
+ squid_off_t max_objsize;
+ RemovalPolicy *repl;
+ int removals;
+ int scanned;
+ struct {
+ unsigned int selected:1;
+ unsigned int read_only:1;
+ } flags;
+ STINIT *init; /* Initialise the fs */
+ STCHECKCONFIG *checkconfig; /* Verify configuration */
+ STNEWFS *newfs; /* Create a new fs */
+ STDUMP *dump; /* Dump fs config snippet */
+ STFREE *freefs; /* Free the fs data */
+ STDBLCHECK *dblcheck; /* Double check the obj integrity */
+ STSTATFS *statfs; /* Dump fs statistics */
+ STMAINTAINFS *maintainfs; /* Replacement maintainence */
+ STCHECKOBJ *checkobj; /* Check if the fs will store an object */
+ STCHECKLOADAV *checkload; /* Check if the fs is getting overloaded .. */
+ /* These two are notifications */
+ STREFOBJ *refobj; /* Reference this object */
+ STUNREFOBJ *unrefobj; /* Unreference this object */
+ STCALLBACK *callback; /* Handle pending callbacks */
+ STSYNC *sync; /* Sync the directory */
+ struct {
+ STOBJCREATE *create;
+ STOBJOPEN *open;
+ STOBJCLOSE *close;
+ STOBJREAD *read;
+ STOBJWRITE *write;
+ STOBJUNLINK *unlink;
+ STOBJRECYCLE *recycle;
+ } obj;
+ struct {
+ STLOGOPEN *open;
+ STLOGCLOSE *close;
+ STLOGWRITE *write;
+ struct {
+ STLOGCLEANSTART *start;
+ STLOGCLEANNEXTENTRY *nextentry;
+ STLOGCLEANWRITE *write;
+ STLOGCLEANDONE *done;
+ void *state;
+ } clean;
+ int writes_since_clean;
+ } log;
+ struct {
+ int blksize;
+ } fs;
+ void *fsdata;
+};
+
+struct _request_flags {
+ unsigned int range:1;
+ unsigned int nocache:1;
+ unsigned int ims:1;
+ unsigned int auth:1;
+ unsigned int cachable:1;
+ unsigned int hierarchical:1;
+ unsigned int loopdetect:1;
+ unsigned int proxy_keepalive:1;
+ unsigned int proxying:1; /* this should be killed, also in httpstateflags */
+ unsigned int refresh:1;
+ unsigned int redirected:1;
+ unsigned int need_validation:1;
+#if HTTP_VIOLATIONS
+ 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;
+ unsigned int must_keepalive:1;
+ unsigned int connection_auth:1; /* Request wants connection oriented auth */
+ unsigned int connection_proxy_auth:1; /* Request wants connection oriented auth */
+ unsigned int no_connection_auth:1; /* Connection oriented auth can not be supported */
+ unsigned int pinned:1; /* Request seont on a pinned connection */
+ unsigned int auth_sent:1; /* Authentication forwarded */
+#if LINUX_TPROXY
+ unsigned int tproxy:1;
+#endif
+ unsigned int collapsed:1; /* This request was collapsed. Don't trust the store entry to be valid */
+};
+
+struct _link_list {
+ void *ptr;
+ struct _link_list *next;
+};
+
+struct _storeIOState {
+ sdirno swap_dirn;
+ sfileno swap_filen;
+ StoreEntry *e; /* Need this so the FS layers can play god */
+ mode_t mode;
+ squid_off_t st_size; /* do stat(2) after read open */
+ squid_off_t offset; /* current on-disk offset pointer */
+ squid_off_t write_offset; /* current storeWrite offset pointer */
+ STFNCB *file_callback; /* called on delayed sfileno assignments */
+ STIOCB *callback;
+ void *callback_data;
+ struct {
+ STRCB *callback;
+ void *callback_data;
+ } read;
+ struct {
+ unsigned int closing:1; /* debugging aid */
+ } flags;
+ void *fsstate;
+};
+
+struct _request_t {
+ method_t method;
+ protocol_t protocol;
+ char login[MAX_LOGIN_SZ];
+ char host[SQUIDHOSTNAMELEN + 1];
+ auth_user_request_t *auth_user_request;
+ u_short port;
+ String urlpath;
+ char *canonical;
+ int link_count; /* free when zero */
+ request_flags flags;
+ HttpHdrCc *cache_control;
+ HttpHdrRange *range;
+ http_version_t http_ver;
+ time_t ims;
+ int imslen;
+ int max_forwards;
+ /* these in_addr's could probably be sockaddr_in's */
+ in_port_t client_port;
+ struct in_addr client_addr;
+#if FOLLOW_X_FORWARDED_FOR
+ struct in_addr indirect_client_addr; /* after following X-Forwarded-For */
+#endif /* FOLLOW_X_FORWARDED_FOR */
+ struct in_addr my_addr;
+ unsigned short my_port;
+ HttpHeader header;
+ squid_off_t content_length;
+ HierarchyLogEntry hier;
+ err_type err_type;
+ char *peer_login; /* Configured peer login:password */
+ time_t lastmod; /* Used on refreshes */
+ char *vary_hdr; /* Used when varying entities are detected. Changes how the store key is calculated */
+ char *vary_headers; /* Used when varying entities are detected. Changes how the store key is calculated */
+ String vary_encoding; /* Used when varying entities are detected. Changes how the store key is calculated. */
+ VaryData *vary;
+ Array *etags; /* possible known entity tags (Vary MISS) */
+ char *etag; /* current entity tag, cache validation */
+ 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 */
+ const char *extacl_user; /* User name returned by extacl lookup */
+ const char *extacl_passwd; /* Password returned by extacl lookup */
+#if FOLLOW_X_FORWARDED_FOR
+ /* XXX a list of IP addresses would be a better data structure
+ * than this String */
+ String x_forwarded_for_iterator;
+#endif /* FOLLOW_X_FORWARDED_FOR */
+ ConnStateData *pinned_connection; /* If set then this request is tighly tied to the corresponding client side connetion */
+};
+
+struct _cachemgr_passwd {
+ char *passwd;
+ wordlist *actions;
+ cachemgr_passwd *next;
+};
+
+struct _refresh_t {
+ const char *pattern;
+ regex_t compiled_pattern;
+ time_t min;
+ double pct;
+ time_t max;
+ refresh_t *next;
+ struct {
+ unsigned int icase:1;
+#if HTTP_VIOLATIONS
+ unsigned int override_expire:1;
+ unsigned int override_lastmod:1;
+ unsigned int reload_into_ims:1;
+ unsigned int ignore_reload:1;
+ unsigned int ignore_no_cache:1;
+ unsigned int ignore_private:1;
+ unsigned int ignore_auth:1;
+#endif
+ } flags;
+};
+
+struct _ErrorState {
+ err_type type;
+ int page_id;
+ http_status http_status;
+ auth_user_request_t *auth_user_request;
+ request_t *request;
+ char *url;
+ int xerrno;
+ char *dnsserver_msg;
+ time_t ttl;
+ struct in_addr src_addr;
+ char *redirect_url;
+ ERCB *callback;
+ void *callback_data;
+ struct {
+ unsigned int flag_cbdata:1;
+ } flags;
+ struct {
+ wordlist *server_msg;
+ char *request;
+ char *reply;
+ } ftp;
+ char *request_hdrs;
+};
+
+/*
+ * "very generic" histogram;
+ * see important comments on hbase_f restrictions in StatHist.c
+ */
+struct _StatHist {
+ int *bins;
+ int capacity;
+ double min;
+ double max;
+ double scale;
+ hbase_f *val_in; /* e.g., log() for log-based histogram */
+ hbase_f *val_out; /* e.g., exp() for log based histogram */
+};
+
+/*
+ * if you add a field to StatCounters,
+ * you MUST sync statCountersInitSpecial, statCountersClean, and statCountersCopy
+ */
+struct _StatCounters {
+ struct {
+ int clients;
+ int requests;
+ int hits;
+ int mem_hits;
+ int disk_hits;
+ int errors;
+ kb_t kbytes_in;
+ kb_t kbytes_out;
+ kb_t hit_kbytes_out;
+ StatHist miss_svc_time;
+ StatHist nm_svc_time;
+ StatHist nh_svc_time;
+ StatHist hit_svc_time;
+ StatHist all_svc_time;
+ } client_http;
+ struct {
+ struct {
+ int requests;
+ int errors;
+ kb_t kbytes_in;
+ kb_t kbytes_out;
+ } all , http, ftp, other;
+ }
+#if HS_FEAT_ICAP
+ icap,
+#endif
+ server;
+ struct {
+ int pkts_sent;
+ int queries_sent;
+ int replies_sent;
+ int pkts_recv;
+ int queries_recv;
+ int replies_recv;
+ int hits_sent;
+ int hits_recv;
+ int replies_queued;
+ int replies_dropped;
+ kb_t kbytes_sent;
+ kb_t q_kbytes_sent;
+ kb_t r_kbytes_sent;
+ kb_t kbytes_recv;
+ kb_t q_kbytes_recv;
+ kb_t r_kbytes_recv;
+ StatHist query_svc_time;
+ StatHist reply_svc_time;
+ int query_timeouts;
+ int times_used;
+ } icp;
+ struct {
+ int pkts_sent;
+ int pkts_recv;
+ } htcp;
+ struct {
+ int requests;
+ } unlink;
+ struct {
+ StatHist svc_time;
+ } dns;
+ struct {
+ int times_used;
+ kb_t kbytes_sent;
+ kb_t kbytes_recv;
+ kb_t memory;
+ int msgs_sent;
+ int msgs_recv;
+#if USE_CACHE_DIGESTS
+ cd_guess_stats guess;
+#endif
+ StatHist on_xition_count;
+ } cd;
+ struct {
+ int times_used;
+ } netdb;
+ int page_faults;
+ int select_loops;
+ int select_fds;
+ double select_time;
+ double cputime;
+ struct timeval timestamp;
+ StatHist comm_icp_incoming;
+ StatHist comm_dns_incoming;
+ StatHist comm_http_incoming;
+ StatHist select_fds_hist;
+ struct {
+ struct {
+ int opens;
+ int closes;
+ int reads;
+ int writes;
+ int seeks;
+ int unlinks;
+ } disk;
+ struct {
+ int accepts;
+ int sockets;
+ int connects;
+ int binds;
+ int closes;
+ int reads;
+ int writes;
+ int recvfroms;
+ int sendtos;
+ } sock;
+ int polls;
+ int selects;
+ } syscalls;
+ int aborted_requests;
+ struct {
+ int files_cleaned;
+ int outs;
+ int ins;
+ } swap;
+};
+
+/* per header statistics */
+struct _HttpHeaderStat {
+ const char *label;
+ HttpHeaderMask *owner_mask;
+
+ StatHist hdrUCountDistr;
+ StatHist fieldTypeDistr;
+ StatHist ccTypeDistr;
+
+ int parsedCount;
+ int ccParsedCount;
+ int destroyedCount;
+ int busyDestroyedCount;
+};
+
+
+struct _tlv {
+ char type;
+ int length;
+ void *value;
+ tlv *next;
+};
+
+/*
+ * Do we need to have the dirn in here? I don't think so, since we already
+ * know the dirn ..
+ */
+struct _storeSwapLogData {
+ char op;
+ sfileno swap_filen;
+ time_t timestamp;
+ time_t lastref;
+ time_t expires;
+ time_t lastmod;
+ squid_file_sz swap_file_sz;
+ u_short refcount;
+ u_short flags;
+ unsigned char key[MD5_DIGEST_CHARS];
+};
+
+struct _storeSwapLogHeader {
+ char op;
+ int version;
+ int record_size;
+};
+
+#if SIZEOF_SQUID_FILE_SZ != SIZEOF_SIZE_T
+struct _storeSwapLogDataOld {
+ char op;
+ sfileno swap_filen;
+ time_t timestamp;
+ time_t lastref;
+ time_t expires;
+ time_t lastmod;
+ size_t swap_file_sz;
+ u_short refcount;
+ u_short flags;
+ unsigned char key[MD5_DIGEST_CHARS];
+};
+
+#endif
+
+
+/* object to track per-action memory usage (e.g. #idle objects) */
+struct _MemMeter {
+ ssize_t level; /* current level (count or volume) */
+ ssize_t hwater_level; /* high water mark */
+ time_t hwater_stamp; /* timestamp of last high water mark change */
+};
+
+/* object to track per-pool memory usage (alloc = inuse+idle) */
+struct _MemPoolMeter {
+ MemMeter alloc;
+ MemMeter inuse;
+ MemMeter idle;
+ gb_t saved;
+ gb_t total;
+};
+
+/* a pool is a [growing] space for objects of the same size */
+struct _MemPool {
+ const char *label;
+ size_t obj_size;
+#if DEBUG_MEMPOOL
+ size_t real_obj_size; /* with alignment */
+#endif
+ Stack pstack; /* stack for free pointers */
+ MemPoolMeter meter;
+#if DEBUG_MEMPOOL
+ MemPoolMeter diff_meter;
+#endif
+};
+
+struct _ClientInfo {
+ hash_link hash; /* must be first */
+ struct in_addr addr;
+ struct {
+ int result_hist[LOG_TYPE_MAX];
+ int n_requests;
+ kb_t kbytes_in;
+ kb_t kbytes_out;
+ kb_t hit_kbytes_out;
+ } Http, Icp;
+ struct {
+ time_t time;
+ int n_req;
+ int n_denied;
+ } cutoff;
+ int n_established; /* number of current established connections */
+ time_t last_seen;
+};
+
+struct _CacheDigest {
+ /* public, read-only */
+ char *mask; /* bit mask */
+ int mask_size; /* mask size in bytes */
+ int capacity; /* expected maximum for .count, not a hard limit */
+ int bits_per_entry; /* number of bits allocated for each entry from capacity */
+ int count; /* number of digested entries */
+ int del_count; /* number of deletions performed so far */
+};
+
+struct _FwdServer {
+ peer *peer; /* NULL --> origin server */
+ hier_code code;
+ FwdServer *next;
+};
+
+struct _FwdState {
+ int client_fd; /* XXX unnecessary */
+ StoreEntry *entry;
+ request_t *request;
+ FwdServer *servers;
+ int server_fd;
+ ErrorState *err;
+ time_t start;
+ int n_tries;
+ int origin_tries;
+#if WIP_FWD_LOG
+ http_status last_status;
+#endif
+ struct {
+ unsigned int dont_retry:1;
+ unsigned int ftp_pasv_failed:1;
+ } flags;
+#if LINUX_NETFILTER
+ struct sockaddr_in src;
+#endif
+};
+
+#if USE_HTCP
+struct _htcpReplyData {
+ int hit;
+ HttpHeader hdr;
+ u_num32 msg_id;
+ double version;
+ struct {
+ /* cache-to-origin */
+ double rtt;
+ int samp;
+ int hops;
+ } cto;
+};
+
+#endif
+
+
+struct _helper_request {
+ char *buf;
+ HLPCB *callback;
+ void *data;
+ struct timeval dispatch_time;
+};
+
+struct _helper_stateful_request {
+ char *buf;
+ HLPSCB *callback;
+ void *data;
+ struct timeval dispatch_time;
+};
+
+
+struct _helper {
+ wordlist *cmdline;
+ dlink_list servers;
+ dlink_list queue;
+ const char *id_name;
+ int n_to_start;
+ int n_running;
+ int n_active;
+ int ipc_type;
+ int concurrency;
+ time_t last_queue_warn;
+ struct {
+ int requests;
+ int replies;
+ int queue_size;
+ int max_queue_size;
+ int avg_svc_time;
+ } stats;
+ time_t last_restart;
+};
+
+struct _helper_stateful {
+ wordlist *cmdline;
+ dlink_list servers;
+ dlink_list queue;
+ const char *id_name;
+ int n_to_start;
+ int n_running;
+ int n_active;
+ int ipc_type;
+ int concurrency;
+ MemPool *datapool;
+ HLPSAVAIL *IsAvailable;
+ HLPSRESET *Reset;
+ time_t last_queue_warn;
+ struct {
+ int requests;
+ int replies;
+ int queue_size;
+ int max_queue_size;
+ int avg_svc_time;
+ } stats;
+ time_t last_restart;
+};
+
+struct _helper_server {
+ int index;
+ int pid;
+ int rfd;
+ int wfd;
+ MemBuf wqueue;
+ char *rbuf;
+ size_t rbuf_sz;
+ int roffset;
+ dlink_node link;
+ helper *parent;
+ helper_request **requests;
+ struct _helper_flags {
+ unsigned int writing:1;
+ unsigned int closing:1;
+ unsigned int shutdown:1;
+ } flags;
+ struct {
+ int uses;
+ unsigned int pending;
+ } stats;
+ void *hIpc;
+};
+
+
+struct _helper_stateful_server {
+ int index;
+ int pid;
+ int rfd;
+ int wfd;
+ char *buf;
+ size_t buf_sz;
+ int offset;
+ struct timeval dispatch_time;
+ struct timeval answer_time;
+ dlink_node link;
+ statefulhelper *parent;
+ helper_stateful_request *request;
+ struct _helper_stateful_flags {
+ unsigned int alive:1;
+ unsigned int busy:1;
+ unsigned int closing:1;
+ unsigned int shutdown:1;
+ unsigned int reserved:1;
+ } flags;
+ struct {
+ int uses;
+ int submits;
+ int releases;
+ } stats;
+ void *data; /* State data used by the calling routines */
+ void *hIpc;
+};
+
+/*
+ * use this when you need to pass callback data to a blocking
+ * operation, but you don't want to add that pointer to cbdata
+ */
+struct _generic_cbdata {
+ void *data;
+};
+
+struct _store_rebuild_data {
+ int objcount; /* # objects successfully reloaded */
+ int expcount; /* # objects expired */
+ int scancount; /* # entries scanned or read from state file */
+ int clashcount; /* # swapfile clashes avoided */
+ int dupcount; /* # duplicates purged */
+ int cancelcount; /* # SWAP_LOG_DEL objects purged */
+ int invalid; /* # bad lines */
+ int badflags; /* # bad e->flags */
+ int bad_log_op;
+ int zero_object_sz;
+};
+
+/*
+ * This defines an fs type
+ */
+
+struct _storefs_entry {
+ const char *typestr;
+ STFSPARSE *parsefunc;
+ STFSRECONFIGURE *reconfigurefunc;
+ STFSSHUTDOWN *donefunc;
+};
+
+/*
+ * This defines an repl type
+ */
+
+struct _storerepl_entry {
+ const char *typestr;
+ REMOVALPOLICYCREATE *create;
+};
+
+/*
+ * Async disk IO - this defines a async disk io queue
+ */
+
+struct _diskd_queue {
+ int smsgid; /* send sysvmsg id */
+ int rmsgid; /* recv sysvmsg id */
+ int wfd; /* queue file descriptor ? */
+ int away; /* number of requests away */
+ int sent_count; /* number of messages sent */
+ int recv_count; /* number of messages received */
+ struct {
+ char *buf; /* shm buffer */
+ link_list *stack;
+ int id; /* sysvshm id */
+ } shm;
+};
+
+struct _Logfile {
+ int fd;
+ char path[MAXPATHLEN];
+ char *buf;
+ size_t bufsz;
+ ssize_t offset;
+ struct {
+ unsigned int fatal;
+ unsigned int syslog;
+ } flags;
+ int syslog_priority;
+};
+
+struct _logformat {
+ char *name;
+ logformat_token *format;
+ logformat *next;
+};
+
+struct _customlog {
+ char *filename;
+ acl_list *aclList;
+ logformat *logFormat;
+ Logfile *logfile;
+ customlog *next;
+ enum {
+ CLF_UNKNOWN,
+ CLF_AUTO,
+ CLF_CUSTOM,
+ CLF_SQUID,
+ CLF_COMMON,
+ CLF_NONE
+ } type;
+};
+
+struct cache_dir_option {
+ const char *name;
+ void (*parse) (SwapDir * sd, const char *option, const char *value, int reconfiguring);
+ void (*dump) (StoreEntry * e, const char *option, SwapDir * sd);
+};
+
+struct error_map_entry {
+ struct error_map_entry *next;
+ char *value;
+ int status;
+};
+struct _errormap {
+ errormap *next;
+ char *url;
+ struct error_map_entry *map;
+};
+
+struct _VaryData {
+ char *key;
+ char *etag;
+ Array etags;
+};
+
+#endif /* SQUID_STRUCTS_H */
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/f3/60c7157c6888001b16add8656805b17d squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/f3/60c7157c6888001b16add8656805b17d
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/f3/60c7157c6888001b16add8656805b17d 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/f3/60c7157c6888001b16add8656805b17d 2006-12-10 16:09:19.000000000 +0200
@@ -0,0 +1,5286 @@
+
+#
+# $Id: cf.data.pre,v 1.374 2006/10/12 20:48:48 wessels Exp $
+#
+#
+# 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) 2000 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.
+#
+
+COMMENT_START
+ WELCOME TO SQUID @VERSION@
+ ----------------------------
+
+ This is the default Squid configuration file. You may wish
+ to look at the Squid home page (http://www.squid-cache.org/)
+ for the FAQ and other documentation.
+
+ The default Squid config file shows what the defaults for
+ various options happen to be. If you don't need to change the
+ default, you shouldn't uncomment the line. Doing so may cause
+ run-time problems. In some cases "none" refers to no default
+ setting at all, while in other cases it refers to a valid
+ option - the comments for that keyword indicate if this is the
+ case.
+
+COMMENT_END
+
+COMMENT_START
+ NETWORK OPTIONS
+ -----------------------------------------------------------------------------
+COMMENT_END
+
+NAME: http_port ascii_port
+TYPE: http_port_list
+DEFAULT: none
+LOC: Config.Sockaddr.http
+DOC_START
+ Usage: port [options]
+ hostname:port [options]
+ 1.2.3.4:port [options]
+
+ The socket addresses where Squid will listen for HTTP client
+ requests. You may specify multiple socket addresses.
+ There are three forms: port alone, hostname with port, and
+ IP address with port. If you specify a hostname or IP
+ address, Squid binds the socket to that specific
+ address. This replaces the old 'tcp_incoming_address'
+ option. Most likely, you do not need to bind to a specific
+ address, so you can use the port number alone.
+
+ The default port number is 3128.
+
+ If you are running Squid in accelerator mode, you
+ probably want to listen on port 80 also, or instead.
+
+ The -a command line option will override the *first* port
+ number listed here. That option will NOT override an IP
+ address, however.
+
+ You may specify multiple socket addresses on multiple lines.
+
+ options are:
+ transparent Support for transparent proxies
+ vhost Accelerator using Host directive
+ vport Accelerator with IP virtual host support
+ vport= As above, but uses specified port number
+ rather than the http_port number.
+ defaultsite= Main web site name for accelerators.
+ urlgroup= Default urlgroup to mark requests
+ with (see also acl urlgroup and
+ url_rewrite_program)
+ protocol= Protocol to reconstruct accelerated
+ requests with. Defaults to http.
+ no-connection-auth
+ Prevent forwarding of Microsoft
+ connection oriented authentication
+ (NTLM, Negotiate and Kerberos)
+ tproxy Support Linux TPROXY for spoofing
+ outgoing connections using the client
+ IP address.
+
+ If you run Squid on a dual-homed machine with an internal
+ and an external interface we recommend you to specify the
+ internal address:port in http_port. This way Squid will only be
+ visible on the internal address.
+
+NOCOMMENT_START
+# Squid normally listens to port 3128
+http_port 3128
+NOCOMMENT_END
+DOC_END
+
+NAME: https_port
+IFDEF: USE_SSL
+TYPE: https_port_list
+DEFAULT: none
+LOC: Config.Sockaddr.https
+DOC_START
+ Usage: [ip:]port cert=certificate.pem [key=key.pem] [options...]
+
+ The socket address where Squid will listen for HTTPS client
+ requests.
+
+ This is really only useful for situations where you are running
+ squid in accelerator mode and you want to do the SSL work at the
+ accelerator level.
+
+ You may specify multiple socket addresses on multiple lines,
+ each with their own SSL certificate and/or options.
+
+ Options:
+
+ defaultsite= The name of the https site presented on
+ this port.
+
+ urlgroup= Default urlgroup to mark requests with (see
+ also acl urlgroup and url_rewrite_program)
+
+ protocol= Protocol to reconstruct accelerated requests
+ with. Defaults to https.
+
+ cert= Path to SSL certificate (PEM format)
+
+ key= Path to SSL private key file (PEM format)
+ if not specified, the certificate file is
+ assumed to be a combined certificate and
+ key file
+
+ version= The version of SSL/TLS supported
+ 1 automatic (default)
+ 2 SSLv2 only
+ 3 SSLv3 only
+ 4 TLSv1 only
+
+ cipher= Colon separated list of supported ciphers
+
+ options= Various SSL engine options. The most important
+ being:
+ NO_SSLv2 Disallow the use of SSLv2
+ NO_SSLv3 Disallow the use of SSLv3
+ NO_TLSv1 Disallow the use of TLSv1
+ SINGLE_DH_USE Always create a new key when using
+ temporary/ephemeral DH key exchanges
+ See src/ssl_support.c or OpenSSL SSL_CTX_set_options
+ documentation for a complete list of options.
+
+ clientca= File containing the list of CAs to use when
+ requesting a client certificate
+
+ cafile= File containing additional CA certificates to
+ use when verifying client certificates. If unset
+ clientca will be used.
+
+ capath= Directory containing additional CA certificates
+ and CRL lists to use when verifying client certificates
+
+ crlfile= File of additional CRL lists to use when verifying
+ the client certificate, in addition to CRLs stored in
+ the capath. Implies VERIFY_CRL flag below.
+
+ dhparams= File containing DH parameters for temporary/ephemeral
+ DH key exchanges
+
+ sslflags= Various flags modifying the use of SSL:
+ DELAYED_AUTH
+ Don't request client certificates
+ immediately, but wait until acl processing
+ requires a certificate (not yet implemented)
+ NO_DEFAULT_CA
+ Don't use the default CA lists built in
+ to OpenSSL.
+ NO_SESSION_REUSE
+ Don't allow for session reuse. Each connection
+ will result in a new SSL session.
+ VERIFY_CRL
+ Verify CRL lists when accepting client
+ certificates
+ VERIFY_CRL_ALL
+ Verify CRL lists for all certificates in the
+ client certificate chain
+
+ sslcontext= SSL session ID context identifier.
+
+DOC_END
+
+NAME: ssl_unclean_shutdown
+IFDEF: USE_SSL
+TYPE: onoff
+DEFAULT: off
+LOC: Config.SSL.unclean_shutdown
+DOC_START
+ Some browsers (especially MSIE) bugs out on SSL shutdown
+ messages.
+DOC_END
+
+NAME: ssl_engine
+IFDEF: USE_SSL
+TYPE: string
+LOC: Config.SSL.ssl_engine
+DEFAULT: none
+DOC_START
+ The OpenSSL engine to use. You will need to set this if you
+ would like to use hardware SSL acceleration for example.
+DOC_END
+
+NAME: sslproxy_client_certificate
+IFDEF: USE_SSL
+DEFAULT: none
+LOC: Config.ssl_client.cert
+TYPE: string
+DOC_START
+ Client SSL Certificate to use when proxying https:// URLs
+DOC_END
+
+NAME: sslproxy_client_key
+IFDEF: USE_SSL
+DEFAULT: none
+LOC: Config.ssl_client.key
+TYPE: string
+DOC_START
+ Client SSL Key to use when proxying https:// URLs
+DOC_END
+
+NAME: sslproxy_version
+IFDEF: USE_SSL
+DEFAULT: 1
+LOC: Config.ssl_client.version
+TYPE: int
+DOC_START
+ SSL version level to use when proxying https:// URLs
+DOC_END
+
+NAME: sslproxy_options
+IFDEF: USE_SSL
+DEFAULT: none
+LOC: Config.ssl_client.options
+TYPE: string
+DOC_START
+ SSL engine options to use when proxying https:// URLs
+DOC_END
+
+NAME: sslproxy_cipher
+IFDEF: USE_SSL
+DEFAULT: none
+LOC: Config.ssl_client.cipher
+TYPE: string
+DOC_START
+ SSL cipher list to use when proxying https:// URLs
+DOC_END
+
+NAME: sslproxy_cafile
+IFDEF: USE_SSL
+DEFAULT: none
+LOC: Config.ssl_client.cafile
+TYPE: string
+DOC_START
+DOC_END
+
+NAME: sslproxy_capath
+IFDEF: USE_SSL
+DEFAULT: none
+LOC: Config.ssl_client.capath
+TYPE: string
+DOC_START
+DOC_END
+
+NAME: sslproxy_flags
+IFDEF: USE_SSL
+DEFAULT: none
+LOC: Config.ssl_client.flags
+TYPE: string
+DOC_START
+DOC_END
+
+NAME: sslpassword_program
+IFDEF: USE_SSL
+DEFAULT: none
+LOC: Config.Program.ssl_password
+TYPE: string
+DOC_START
+ Specify a program used for entering SSL key passphrases
+ when using encrypted SSL certificate keys. If not specified
+ keys must either be unencrypted, or Squid started with the -N
+ option to allow it to query interactively for the passphrase.
+DOC_END
+
+NAME: icp_port udp_port
+TYPE: ushort
+DEFAULT: @DEFAULT_ICP_PORT@
+LOC: Config.Port.icp
+DOC_START
+ The port number where Squid sends and receives ICP queries to
+ and from neighbor caches. Default is 3130. To disable use
+ "0". May be overridden with -u on the command line.
+DOC_END
+
+NAME: htcp_port
+IFDEF: USE_HTCP
+TYPE: ushort
+DEFAULT: 4827
+LOC: Config.Port.htcp
+DOC_START
+ The port number where Squid sends and receives HTCP queries to
+ and from neighbor caches. Default is 4827. To disable use
+ "0".
+DOC_END
+
+
+NAME: mcast_groups
+TYPE: wordlist
+LOC: Config.mcast_group_list
+DEFAULT: none
+DOC_START
+ This tag specifies a list of multicast groups which your server
+ should join to receive multicasted ICP queries.
+
+ NOTE! Be very careful what you put here! Be sure you
+ understand the difference between an ICP _query_ and an ICP
+ _reply_. This option is to be set only if you want to RECEIVE
+ multicast queries. Do NOT set this option to SEND multicast
+ ICP (use cache_peer for that). ICP replies are always sent via
+ unicast, so this option does not affect whether or not you will
+ receive replies from multicast group members.
+
+ You must be very careful to NOT use a multicast address which
+ is already in use by another group of caches.
+
+ If you are unsure about multicast, please read the Multicast
+ chapter in the Squid FAQ (http://www.squid-cache.org/FAQ/).
+
+ Usage: mcast_groups 239.128.16.128 224.0.1.20
+
+ By default, Squid doesn't listen on any multicast groups.
+DOC_END
+
+
+NAME: udp_incoming_address
+TYPE: address
+LOC:Config.Addrs.udp_incoming
+DEFAULT: 0.0.0.0
+DOC_NONE
+
+NAME: udp_outgoing_address
+TYPE: address
+LOC: Config.Addrs.udp_outgoing
+DEFAULT: 255.255.255.255
+DOC_START
+ udp_incoming_address is used for the ICP socket receiving packets
+ from other caches.
+ udp_outgoing_address is used for ICP packets sent out to other
+ caches.
+
+ The default behavior is to not bind to any specific address.
+
+ A udp_incoming_address value of 0.0.0.0 indicates Squid
+ should listen for UDP messages on all available interfaces.
+
+ If udp_outgoing_address is set to 255.255.255.255 (the default)
+ it will use the same socket as udp_incoming_address. Only
+ change this if you want to have ICP queries sent using another
+ address than where this Squid listens for ICP queries from other
+ caches.
+
+ NOTE, udp_incoming_address and udp_outgoing_address can not
+ have the same value since they both use port 3130.
+DOC_END
+
+COMMENT_START
+ OPTIONS WHICH AFFECT THE NEIGHBOR SELECTION ALGORITHM
+ -----------------------------------------------------------------------------
+COMMENT_END
+
+NAME: cache_peer
+TYPE: peer
+DEFAULT: none
+LOC: Config.peers
+DOC_START
+ To specify other caches in a hierarchy, use the format:
+
+ cache_peer hostname type http_port icp_port [options]
+
+ For example,
+
+ # proxy icp
+ # hostname type port port options
+ # -------------------- -------- ----- ----- -----------
+ cache_peer parent.foo.net parent 3128 3130 [proxy-only]
+ cache_peer sib1.foo.net sibling 3128 3130 [proxy-only]
+ cache_peer sib2.foo.net sibling 3128 3130 [proxy-only]
+
+ type: either 'parent', 'sibling', or 'multicast'.
+
+ proxy_port: The port number where the cache listens for proxy
+ requests.
+
+ icp_port: Used for querying neighbor caches about
+ objects. To have a non-ICP neighbor
+ specify '7' for the ICP port and make sure the
+ neighbor machine has the UDP echo port
+ enabled in its /etc/inetd.conf file.
+
+ options: proxy-only
+ weight=n
+ ttl=n
+ no-query
+ default
+ round-robin
+ multicast-responder
+ closest-only
+ no-digest
+ no-netdb-exchange
+ no-delay
+ login=user:password | PASS | *:password
+ connect-timeout=nn
+ digest-url=url
+ allow-miss
+ max-conn
+ htcp
+ htcp-oldsquid
+ carp-load-factor
+ originserver
+ userhash
+ sourcehash
+ name=xxx
+ monitorurl=url
+ monitorsize=sizespec
+ monitorinterval=seconds
+ monitortimeout=seconds
+ group=name
+ forceddomain=name
+ ssl
+ sslcert=/path/to/ssl/certificate
+ sslkey=/path/to/ssl/key
+ sslversion=1|2|3|4
+ sslcipher=...
+ ssloptions=...
+ front-end-https[=on|auto]
+ connection-auth[=on|off|auto]
+
+ use 'proxy-only' to specify objects fetched
+ from this cache should not be saved locally.
+
+ use 'weight=n' to specify a weighted parent.
+ The weight must be an integer. The default weight
+ is 1, larger weights are favored more.
+
+ use 'ttl=n' to specify a IP multicast TTL to use
+ when sending an ICP queries to this address.
+ Only useful when sending to a multicast group.
+ Because we don't accept ICP replies from random
+ hosts, you must configure other group members as
+ peers with the 'multicast-responder' option below.
+
+ use 'no-query' to NOT send ICP queries to this
+ neighbor.
+
+ use 'default' if this is a parent cache which can
+ be used as a "last-resort." You should probably
+ only use 'default' in situations where you cannot
+ use ICP with your parent cache(s).
+
+ use 'round-robin' to define a set of parents which
+ should be used in a round-robin fashion in the
+ absence of any ICP queries.
+
+ 'multicast-responder' indicates the named peer
+ is a member of a multicast group. ICP queries will
+ not be sent directly to the peer, but ICP replies
+ will be accepted from it.
+
+ 'closest-only' indicates that, for ICP_OP_MISS
+ replies, we'll only forward CLOSEST_PARENT_MISSes
+ and never FIRST_PARENT_MISSes.
+
+ use 'no-digest' to NOT request cache digests from
+ this neighbor.
+
+ 'no-netdb-exchange' disables requesting ICMP
+ RTT database (NetDB) from the neighbor.
+
+ use 'no-delay' to prevent access to this neighbor
+ from influencing the delay pools.
+
+ use 'login=user:password' if this is a personal/workgroup
+ proxy and your parent requires proxy authentication.
+ Note: The string can include URL escapes (i.e. %20 for
+ spaces). This also means % must be written as %%.
+
+ use 'login=PASS' to forward authentication to the peer.
+ Needed if the peer requires login.
+ Note: To combine this with local authentication the Basic
+ authentication scheme must be used, and both servers must
+ share the same user database as HTTP only allows for
+ a single login (one for proxy, one for origin server).
+
+ use 'login=*:password' to pass the username to the
+ upstream cache, but with a fixed password. This is meant
+ to be used when the peer is in another administrative
+ domain, but it is still needed to identify each user.
+ The star can optionally be followed by some extra
+ information which is added to the username. This can
+ be used to identify this proxy to the peer, similar to
+ the login=username:password option above.
+
+ use 'connect-timeout=nn' to specify a peer
+ specific connect timeout (also see the
+ peer_connect_timeout directive)
+
+ use 'digest-url=url' to tell Squid to fetch the cache
+ digest (if digests are enabled) for this host from
+ the specified URL rather than the Squid default
+ location.
+
+ use 'allow-miss' to disable Squid's use of only-if-cached
+ when forwarding requests to siblings. This is primarily
+ useful when icp_hit_stale is used by the sibling. To
+ extensive use of this option may result in forwarding
+ loops, and you should avoid having two-way peerings
+ with this option. (for example to deny peer usage on
+ requests from peer by denying cache_peer_access if the
+ source is a peer)
+
+ use 'max-conn' to limit the amount of connections Squid
+ may open to this peer.
+
+ use 'htcp' to send HTCP, instead of ICP, queries
+ to the neighbor. You probably also want to
+ set the "icp port" to 4827 instead of 3130.
+
+ use 'htcp-oldsquid' to send HTCP to old Squid versions
+
+ use 'carp-load-factor=f' to define a parent
+ cache as one participating in a CARP array.
+ The 'f' values for all CARP parents must add
+ up to 1.0.
+
+ 'originserver' causes this parent peer to be contacted as
+ a origin server. Meant to be used in accelerator setups.
+
+ use 'userhash' to load-balance amongst a set of parents
+ based on the client proxy_auth or ident username.
+
+ use 'sourcehash' to load-balanse amongs a set of parents
+ based on the client source ip.
+
+ use 'name=xxx' if you have multiple peers on the same
+ host but different ports. This name can then be used to
+ differentiate the peers in cache_peer_access and similar
+ directives.
+
+ use 'monitorurl=url' to have periodically request a given
+ URL from the peer, and only consider the peer as alive
+ if this monitoring is successful (default none)
+
+ use 'monitorsize=min[-max]' to limit the size range of
+ 'monitorurl' replies considered valid. Defaults to 0 to
+ accept any size replies as valid.
+
+ use 'monitorinterval=seconds' to change frequency of
+ how often the peer is monitored with 'monitorurl'
+ (default 300 for a 5 minute interval). If set to 0
+ then monitoring is disabled even if a URL is defined.
+
+ use 'monitortimeout=seconds' to change the timeout of
+ 'monitorurl'. Defaults to 'monitorinterval'.
+
+ use 'forceddomain=name' to forcibly set the Host header
+ of requests forwarded to this peer. Useful in accelerator
+ setups where the server (peer) expects a certain domain
+ name and using redirectors to feed this domain name
+ is not feasible.
+
+ use 'ssl' to indicate that connections to this peer should
+ bs SSL/TLS encrypted.
+
+ use 'sslcert=/path/to/ssl/certificate' to specify a client
+ SSL certificate to use when connecting to this peer.
+
+ use 'sslkey=/path/to/ssl/key' to specify the private SSL
+ key corresponding to sslcert above. If 'sslkey' is not
+ specified then 'sslcert' is assumed to reference a
+ combined file containing both the certificate and the key.
+
+ use sslversion=1|2|3|4 to specify the SSL version to use
+ when connecting to this peer
+ 1 = automatic (default)
+ 2 = SSL v2 only
+ 3 = SSL v3 only
+ 4 = TLS v1 only
+
+ use sslcipher=... to specify the list of valid SSL ciphers
+ to use when connecting to this peer.
+
+ use ssloptions=... to specify various SSL engine options:
+ NO_SSLv2 Disallow the use of SSLv2
+ NO_SSLv3 Disallow the use of SSLv3
+ NO_TLSv1 Disallow the use of TLSv1
+ See src/ssl_support.c or the OpenSSL documentation for
+ a more complete list.
+
+ use sslcafile=... to specify a file containing
+ additional CA certificates to use when verifying the
+ peer certificate.
+
+ use sslcapath=... to specify a directory containing
+ additional CA certificates to use when verifying the
+ peer certificate.
+
+ use sslcrlfile=... to specify a certificate revocation
+ list file to use when verifying the peer certificate.
+
+ use sslflags=... to specify various flags modifying the
+ SSL implementation:
+ DONT_VERIFY_PEER
+ Accept certificates even if they fail to
+ verify.
+ NO_DEFAULT_CA
+ Don't use the default CA list built in
+ to OpenSSL.
+
+ use ssldomain= to specify the peer name as advertised
+ in it's certificate. Used for verifying the correctness
+ of the received peer certificate. If not specified the
+ peer hostname will be used.
+
+ use front-end-https to enable the "Front-End-Https: On"
+ header needed when using Squid as a SSL frontend in front
+ of Microsoft OWA. See MS KB document Q307347 for details
+ on this header. If set to auto then the header will
+ only be added if the request is forwarded as a https://
+ URL.
+
+ use connection-auth=off to tell Squid that this peer does
+ not support Microsoft connection oriented authentication,
+ and any such challenges received from there should be
+ ignored. Default is auto to automatically determine the
+ status of the peer.
+
+ NOTE: non-ICP/HTCP neighbors must be specified as 'parent'.
+DOC_END
+
+NAME: cache_peer_domain cache_host_domain
+TYPE: hostdomain
+DEFAULT: none
+LOC: none
+DOC_START
+ Use to limit the domains for which a neighbor cache will be
+ queried. Usage:
+
+ cache_peer_domain cache-host domain [domain ...]
+ cache_peer_domain cache-host !domain
+
+ For example, specifying
+
+ cache_peer_domain parent.foo.net .edu
+
+ has the effect such that UDP query packets are sent to
+ 'bigserver' only when the requested object exists on a
+ server in the .edu domain. Prefixing the domain name
+ with '!' means the cache will be queried for objects
+ NOT in that domain.
+
+ NOTE: * Any number of domains may be given for a cache-host,
+ either on the same or separate lines.
+ * When multiple domains are given for a particular
+ cache-host, the first matched domain is applied.
+ * Cache hosts with no domain restrictions are queried
+ for all requests.
+ * There are no defaults.
+ * There is also a 'cache_peer_access' tag in the ACL
+ section.
+DOC_END
+
+
+NAME: neighbor_type_domain
+TYPE: hostdomaintype
+DEFAULT: none
+LOC: none
+DOC_START
+ usage: neighbor_type_domain neighbor parent|sibling domain domain ...
+
+ Modifying the neighbor type for specific domains is now
+ possible. You can treat some domains differently than the the
+ default neighbor type specified on the 'cache_peer' line.
+ Normally it should only be necessary to list domains which
+ should be treated differently because the default neighbor type
+ applies for hostnames which do not match domains listed here.
+
+EXAMPLE:
+ cache_peer parent cache.foo.org 3128 3130
+ neighbor_type_domain cache.foo.org sibling .com .net
+ neighbor_type_domain cache.foo.org sibling .au .de
+DOC_END
+
+NAME: icp_query_timeout
+COMMENT: (msec)
+DEFAULT: 0
+TYPE: int
+LOC: Config.Timeout.icp_query
+DOC_START
+ Normally Squid will automatically determine an optimal ICP
+ query timeout value based on the round-trip-time of recent ICP
+ queries. If you want to override the value determined by
+ Squid, set this 'icp_query_timeout' to a non-zero value. This
+ value is specified in MILLISECONDS, so, to use a 2-second
+ timeout (the old default), you would write:
+
+ icp_query_timeout 2000
+DOC_END
+
+NAME: maximum_icp_query_timeout
+COMMENT: (msec)
+DEFAULT: 2000
+TYPE: int
+LOC: Config.Timeout.icp_query_max
+DOC_START
+ Normally the ICP query timeout is determined dynamically. But
+ sometimes it can lead to very large values (say 5 seconds).
+ Use this option to put an upper limit on the dynamic timeout
+ value. Do NOT use this option to always use a fixed (instead
+ of a dynamic) timeout value. To set a fixed timeout see the
+ 'icp_query_timeout' directive.
+DOC_END
+
+NAME: mcast_icp_query_timeout
+COMMENT: (msec)
+DEFAULT: 2000
+TYPE: int
+LOC: Config.Timeout.mcast_icp_query
+DOC_START
+ For multicast peers, Squid regularly sends out ICP "probes" to
+ count how many other peers are listening on the given multicast
+ address. This value specifies how long Squid should wait to
+ count all the replies. The default is 2000 msec, or 2
+ seconds.
+DOC_END
+
+NAME: dead_peer_timeout
+COMMENT: (seconds)
+DEFAULT: 10 seconds
+TYPE: time_t
+LOC: Config.Timeout.deadPeer
+DOC_START
+ This controls how long Squid waits to declare a peer cache
+ as "dead." If there are no ICP replies received in this
+ amount of time, Squid will declare the peer dead and not
+ expect to receive any further ICP replies. However, it
+ continues to send ICP queries, and will mark the peer as
+ alive upon receipt of the first subsequent ICP reply.
+
+ This timeout also affects when Squid expects to receive ICP
+ replies from peers. If more than 'dead_peer' seconds have
+ passed since the last ICP reply was received, Squid will not
+ expect to receive an ICP reply on the next query. Thus, if
+ your time between requests is greater than this timeout, you
+ will see a lot of requests sent DIRECT to origin servers
+ instead of to your parents.
+DOC_END
+
+
+NAME: hierarchy_stoplist
+TYPE: wordlist
+DEFAULT: none
+LOC: Config.hierarchy_stoplist
+DOC_START
+ A list of words which, if found in a URL, cause the object to
+ be handled directly by this cache. In other words, use this
+ to not query neighbor caches for certain objects. You may
+ list this option multiple times. Note: never_direct overrides
+ this option.
+NOCOMMENT_START
+#We recommend you to use at least the following line.
+hierarchy_stoplist cgi-bin ?
+NOCOMMENT_END
+DOC_END
+
+
+NAME: cache no_cache
+TYPE: acl_access
+DEFAULT: none
+LOC: Config.accessList.noCache
+DOC_START
+ A list of ACL elements which, if matched, cause the request to
+ not be satisfied from the cache and the reply to not be cached.
+ In other words, use this to force certain objects to never be cached.
+
+ You must use the word 'DENY' to indicate the ACL names which should
+ NOT be cached.
+
+ Default is to allow all to be cached
+NOCOMMENT_START
+#We recommend you to use the following two lines.
+acl QUERY urlpath_regex cgi-bin \?
+cache deny QUERY
+NOCOMMENT_END
+DOC_END
+
+NAME: cache_vary
+TYPE: onoff
+DEFAULT: on
+LOC: Config.onoff.cache_vary
+DOC_START
+ Set to off to disable caching of Vary:in objects.
+DOC_END
+
+NAME: broken_vary_encoding
+TYPE: acl_access
+DEFAULT: none
+LOC: Config.accessList.vary_encoding
+DOC_START
+ Many servers have broken support for on-the-fly Content-Encoding,
+ returning the same ETag on both plain and gzip:ed variants.
+ Vary replies matching this access list will have the cache split
+ on the Accept-Encoding header of the request and not trusting the
+ ETag to be unique.
+
+NOCOMMENT_START
+# Apache mod_gzip and mod_deflate known to be broken so don't trust
+# Apache to signal ETag correctly on such responses
+acl apache rep_header Server ^Apache
+broken_vary_encoding allow apache
+NOCOMMENT_END
+DOC_END
+
+COMMENT_START
+ OPTIONS WHICH AFFECT THE CACHE SIZE
+ -----------------------------------------------------------------------------
+COMMENT_END
+
+NAME: cache_mem
+COMMENT: (bytes)
+TYPE: b_size_t
+DEFAULT: 8 MB
+LOC: Config.memMaxSize
+DOC_START
+ NOTE: THIS PARAMETER DOES NOT SPECIFY THE MAXIMUM PROCESS SIZE.
+ IT ONLY PLACES A LIMIT ON HOW MUCH ADDITIONAL MEMORY SQUID WILL
+ USE AS A MEMORY CACHE OF OBJECTS. SQUID USES MEMORY FOR OTHER
+ THINGS AS WELL. SEE THE SQUID FAQ SECTION 8 FOR DETAILS.
+
+ 'cache_mem' specifies the ideal amount of memory to be used
+ for:
+ * In-Transit objects
+ * Hot Objects
+ * Negative-Cached objects
+
+ Data for these objects are stored in 4 KB blocks. This
+ parameter specifies the ideal upper limit on the total size of
+ 4 KB blocks allocated. In-Transit objects take the highest
+ priority.
+
+ In-transit objects have priority over the others. When
+ additional space is needed for incoming data, negative-cached
+ and hot objects will be released. In other words, the
+ negative-cached and hot objects will fill up any unused space
+ not needed for in-transit objects.
+
+ If circumstances require, this limit will be exceeded.
+ Specifically, if your incoming request rate requires more than
+ 'cache_mem' of memory to hold in-transit objects, Squid will
+ exceed this limit to satisfy the new requests. When the load
+ decreases, blocks will be freed until the high-water mark is
+ reached. Thereafter, blocks will be used to store hot
+ objects.
+DOC_END
+
+
+NAME: cache_swap_low
+COMMENT: (percent, 0-100)
+TYPE: int
+DEFAULT: 90
+LOC: Config.Swap.lowWaterMark
+DOC_NONE
+
+NAME: cache_swap_high
+COMMENT: (percent, 0-100)
+TYPE: int
+DEFAULT: 95
+LOC: Config.Swap.highWaterMark
+DOC_START
+
+ The low- and high-water marks for cache object replacement.
+ Replacement begins when the swap (disk) usage is above the
+ low-water mark and attempts to maintain utilization near the
+ low-water mark. As swap utilization gets close to high-water
+ mark object eviction becomes more aggressive. If utilization is
+ close to the low-water mark less replacement is done each time.
+
+ Defaults are 90% and 95%. If you have a large cache, 5% could be
+ hundreds of MB. If this is the case you may wish to set these
+ numbers closer together.
+DOC_END
+
+NAME: maximum_object_size
+COMMENT: (bytes)
+TYPE: b_size_t
+DEFAULT: 4096 KB
+LOC: Config.Store.maxObjectSize
+DOC_START
+ Objects larger than this size will NOT be saved on disk. The
+ value is specified in kilobytes, and the default is 4MB. If
+ you wish to get a high BYTES hit ratio, you should probably
+ increase this (one 32 MB object hit counts for 3200 10KB
+ hits). If you wish to increase speed more than your want to
+ save bandwidth you should leave this low.
+
+ NOTE: if using the LFUDA replacement policy you should increase
+ this value to maximize the byte hit rate improvement of LFUDA!
+ See replacement_policy below for a discussion of this policy.
+DOC_END
+
+NAME: minimum_object_size
+COMMENT: (bytes)
+TYPE: b_size_t
+DEFAULT: 0 KB
+LOC: Config.Store.minObjectSize
+DOC_START
+ Objects smaller than this size will NOT be saved on disk. The
+ value is specified in kilobytes, and the default is 0 KB, which
+ means there is no minimum.
+DOC_END
+
+NAME: maximum_object_size_in_memory
+COMMENT: (bytes)
+TYPE: b_size_t
+DEFAULT: 8 KB
+LOC: Config.Store.maxInMemObjSize
+DOC_START
+ Objects greater than this size will not be attempted to kept in
+ the memory cache. This should be set high enough to keep objects
+ accessed frequently in memory to improve performance whilst low
+ enough to keep larger objects from hoarding cache_mem.
+DOC_END
+
+NAME: ipcache_size
+COMMENT: (number of entries)
+TYPE: int
+DEFAULT: 1024
+LOC: Config.ipcache.size
+DOC_NONE
+
+NAME: ipcache_low
+COMMENT: (percent)
+TYPE: int
+DEFAULT: 90
+LOC: Config.ipcache.low
+DOC_NONE
+
+NAME: ipcache_high
+COMMENT: (percent)
+TYPE: int
+DEFAULT: 95
+LOC: Config.ipcache.high
+DOC_START
+ The size, low-, and high-water marks for the IP cache.
+DOC_END
+
+NAME: fqdncache_size
+COMMENT: (number of entries)
+TYPE: int
+DEFAULT: 1024
+LOC: Config.fqdncache.size
+DOC_START
+ Maximum number of FQDN cache entries.
+DOC_END
+
+NAME: cache_replacement_policy
+TYPE: removalpolicy
+LOC: Config.replPolicy
+DEFAULT: lru
+DOC_START
+ The cache replacement policy parameter determines which
+ objects are evicted (replaced) when disk space is needed.
+
+ lru : Squid's original list based LRU policy
+ heap GDSF : Greedy-Dual Size Frequency
+ heap LFUDA: Least Frequently Used with Dynamic Aging
+ heap LRU : LRU policy implemented using a heap
+
+ Applies to any cache_dir lines listed below this.
+
+ The LRU policies keeps recently referenced objects.
+
+ The heap GDSF policy optimizes object hit rate by keeping smaller
+ popular objects in cache so it has a better chance of getting a
+ hit. It achieves a lower byte hit rate than LFUDA though since
+ it evicts larger (possibly popular) objects.
+
+ The heap LFUDA policy keeps popular objects in cache regardless of
+ their size and thus optimizes byte hit rate at the expense of
+ hit rate since one large, popular object will prevent many
+ smaller, slightly less popular objects from being cached.
+
+ Both policies utilize a dynamic aging mechanism that prevents
+ cache pollution that can otherwise occur with frequency-based
+ replacement policies.
+
+ NOTE: if using the LFUDA replacement policy you should increase
+ the value of maximum_object_size above its default of 4096 KB to
+ to maximize the potential byte hit rate improvement of LFUDA.
+
+ For more information about the GDSF and LFUDA cache replacement
+ policies see http://www.hpl.hp.com/techreports/1999/HPL-1999-69.html
+ and http://fog.hpl.external.hp.com/techreports/98/HPL-98-173.html.
+DOC_END
+
+NAME: memory_replacement_policy
+TYPE: removalpolicy
+LOC: Config.memPolicy
+DEFAULT: lru
+DOC_START
+ The memory replacement policy parameter determines which
+ objects are purged from memory when memory space is needed.
+
+ See cache_replacement_policy for details.
+DOC_END
+
+
+COMMENT_START
+ LOGFILE PATHNAMES AND CACHE DIRECTORIES
+ -----------------------------------------------------------------------------
+COMMENT_END
+
+NAME: cache_dir
+TYPE: cachedir
+DEFAULT: none
+DEFAULT_IF_NONE: ufs @DEFAULT_SWAP_DIR@ 100 16 256
+LOC: Config.cacheSwap
+DOC_START
+ Usage:
+
+ cache_dir Type Directory-Name Fs-specific-data [options]
+
+ You can specify multiple cache_dir lines to spread the
+ cache among different disk partitions.
+
+ Type specifies the kind of storage system to use. Only "ufs"
+ is built by default. To enable any of the other storage systems
+ see the --enable-storeio configure option.
+
+ 'Directory' is a top-level directory where cache swap
+ files will be stored. If you want to use an entire disk
+ for caching, this can be the mount-point directory.
+ The directory must exist and be writable by the Squid
+ process. Squid will NOT create this directory for you.
+ Only using COSS, a raw disk device or a stripe file can
+ be specified, but the configuration of the "cache_wap_log"
+ tag is mandatory.
+
+ The ufs store type:
+
+ "ufs" is the old well-known Squid storage format that has always
+ been there.
+
+ cache_dir ufs Directory-Name Mbytes L1 L2 [options]
+
+ 'Mbytes' is the amount of disk space (MB) to use under this
+ directory. The default is 100 MB. Change this to suit your
+ configuration. Do NOT put the size of your disk drive here.
+ Instead, if you want Squid to use the entire disk drive,
+ subtract 20% and use that value.
+
+ 'Level-1' is the number of first-level subdirectories which
+ will be created under the 'Directory'. The default is 16.
+
+ 'Level-2' is the number of second-level subdirectories which
+ will be created under each first-level directory. The default
+ is 256.
+
+ The aufs store type:
+
+ "aufs" uses the same storage format as "ufs", utilizing
+ POSIX-threads to avoid blocking the main Squid process on
+ disk-I/O. This was formerly known in Squid as async-io.
+
+ cache_dir aufs Directory-Name Mbytes L1 L2 [options]
+
+ see argument descriptions under ufs above
+
+ The diskd store type:
+
+ "diskd" uses the same storage format as "ufs", utilizing a
+ separate process to avoid blocking the main Squid process on
+ disk-I/O.
+
+ cache_dir diskd Directory-Name Mbytes L1 L2 [options] [Q1=n] [Q2=n]
+
+ see argument descriptions under ufs above
+
+ Q1 specifies the number of unacknowledged I/O requests when Squid
+ stops opening new files. If this many messages are in the queues,
+ Squid won't open new files. Default is 64
+
+ Q2 specifies the number of unacknowledged messages when Squid
+ starts blocking. If this many messages are in the queues,
+ Squid blocks until it receives some replies. Default is 72
+
+ When Q1 < Q2 (the default), the cache directory is optimized
+ for lower response time at the expense of a decrease in hit
+ ratio. If Q1 > Q2, the cache directory is optimized for
+ higher hit ratio at the expense of an increase in response
+ time.
+
+ The COSS store type:
+
+ block-size=n defines the "block size" for COSS cache_dir's.
+ Squid uses file numbers as block numbers. Since file numbers
+ are limited to 24 bits, the block size determines the maximum
+ size of the COSS partition. The default is 512 bytes, which
+ leads to a maximum cache_dir size of 512<<24, or 8 GB. Note
+ you should not change the COSS block size after Squid
+ has written some objects to the cache_dir.
+
+ overwrite-percent=n defines the percentage of disk that COSS
+ must write to before a given object will be moved to the
+ current stripe. A value of "n" closer to 100 will cause COSS
+ to waste less disk space by having multiple copies of an object
+ on disk, but will increase the chances of overwriting a popular
+ object as COSS overwrites stripes. A value of "n" close to 0
+ will cause COSS to keep all current objects in the current COSS
+ stripe at the expense of the hit rate. The default value of 50
+ will allow any given object to be stored on disk a maximum of
+ 2 times.
+
+ max-stripe-waste=n defines the maximum amount of space that COSS
+ will waste in a given stripe (in bytes). When COSS writes data
+ to disk, it will potentially waste up to "max-size" worth of disk
+ space for each 1MB of data written. If "max-size" is set to a
+ large value (ie >256k), this could potentially result in large
+ amounts of wasted disk space. Setting this value to a lower value
+ (ie 64k or 32k) will result in a COSS disk refusing to cache
+ larger objects until the COSS stripe has been filled to within
+ "max-stripe-waste" of the maximum size (1MB).
+
+ membufs=n defines the number of "memory-only" stripes that COSS
+ will use. When an cache hit is performed on a COSS stripe before
+ COSS has reached the overwrite-percent value for that object,
+ COSS will use a series of memory buffers to hold the object in
+ while the data is sent to the client. This will define the maximum
+ number of memory-only buffers that COSS will use. The default value
+ is 10, which will use a maximum of 10MB of memory for buffers.
+
+ maxfullbufs=n defines the maximum number of stripes a COSS partition
+ will have in memory waiting to be freed (either because the disk is
+ under load and the stripe is unwritten, or because clients are still
+ transferring data from objects using the memory). In order to try
+ and maintain a good hit rate under load, COSS will reserve the last
+ 2 full stripes for object hits. (ie a COSS cache_dir will reject
+ new objects when the number of full stripes is 2 less than maxfullbufs)
+
+ Common options:
+
+ read-only, this cache_dir is read only.
+
+ max-size=n, refers to the max object size this storedir supports.
+ It is used to initially choose the storedir to dump the object.
+ Note: To make optimal use of the max-size limits you should order
+ the cache_dir lines with the smallest max-size value first and the
+ ones with no max-size specification last.
+
+ Note that for coss, max-size must be less than COSS_MEMBUF_SZ
+ (hard coded at 1 MB).
+DOC_END
+
+NAME: logformat
+TYPE: logformat
+LOC: Config.Log.logformats
+DEFAULT: none
+DOC_START
+ Usage:
+
+ logformat
+
+ Defines an access log format.
+
+ The is a string with embedded % format codes
+
+ % format codes all follow the same basic structure where all but
+ the formatcode is optional. Output strings are automatically escaped
+ as required according to their context and the output format
+ modifiers are usually not needed, but can be specified if an explicit
+ output format is desired.
+
+ % ["|[|'|#] [-] [[0]width] [{argument}] formatcode
+
+ " output in quoted string format
+ [ output in squid text log format as used by log_mime_hdrs
+ # output in URL quoted format
+ ' output as-is
+
+ - left aligned
+ width field width. If starting with 0 then the
+ output is zero padded
+ {arg} argument such as header name etc
+
+ Format codes:
+
+ >a Client source IP address
+ >A Client FQDN
+ h Request header. Optional header name argument
+ on the format header[:[separator]element]
+ h
+ un User name
+ ul User login
+ ui User ident
+ us User SSL
+ ue User external acl
+ Hs HTTP status code
+ Ss Squid request status (TCP_MISS etc)
+ Sh Squid hierarchy status (DEFAULT_PARENT etc)
+ mt MIME content type
+ rm Request method (GET/POST etc)
+ ru Request URL
+ rv Request protocol version
+ ea Log string returned by external acl
+ a %Ss/%03Hs %a %Ss/%03Hs %h] [%a %ui %un [%tl] "%rm %ru HTTP/%rv" %Hs %a %ui %un [%tl] "%rm %ru HTTP/%rv" %Hs %h" "%{User-Agent}>h" %Ss:%Sh
+DOC_END
+
+NAME: access_log cache_access_log
+TYPE: access_log
+LOC: Config.Log.accesslogs
+DEFAULT: none
+DOC_START
+ These files log client request activities. Has a line every HTTP or
+ ICP request. The format is:
+ access_log [ [acl acl ...]]
+
+ Will log to the specified file using the specified format (which
+ must be defined in a logformat directive) those entries which match
+ ALL the acl's specified (which must be defined in acl clauses).
+ If no acl is specified, all requests will be logged to this file.
+
+ To disable logging of a request use the filepath "none", in which case
+ a logformat name should not be specified.
+
+ To log the request via syslog specify a filepath of "syslog"
+NOCOMMENT_START
+access_log @DEFAULT_ACCESS_LOG@ squid
+NOCOMMENT_END
+DOC_END
+
+NAME: cache_log
+TYPE: string
+DEFAULT: @DEFAULT_CACHE_LOG@
+LOC: Config.Log.log
+DOC_START
+ Cache logging file. This is where general information about
+ your cache's behavior goes. You can increase the amount of data
+ logged to this file with the "debug_options" tag below.
+DOC_END
+
+
+NAME: cache_store_log
+TYPE: string
+DEFAULT: @DEFAULT_STORE_LOG@
+LOC: Config.Log.store
+DOC_START
+ Logs the activities of the storage manager. Shows which
+ objects are ejected from the cache, and which objects are
+ saved and for how long. To disable, enter "none". There are
+ not really utilities to analyze this data, so you can safely
+ disable it.
+DOC_END
+
+
+NAME: cache_swap_log cache_swap_state
+TYPE: string
+LOC: Config.Log.swap
+DEFAULT: none
+DOC_START
+ Location for the cache "swap.state" file. This log file holds
+ the metadata of objects saved on disk. It is used to rebuild
+ the cache during startup. Normally this file resides in each
+ 'cache_dir' directory, but you may specify an alternate
+ pathname here. Note you must give a full filename, not just
+ a directory. Since this is the index for the whole object
+ list you CANNOT periodically rotate it!
+
+ If %s can be used in the file name it will be replaced with a
+ a representation of the cache_dir name where each / is replaced
+ with '.'. This is needed to allow adding/removing cache_dir
+ lines when cache_swap_log is being used.
+
+ If have more than one 'cache_dir', and %s is not used in the name
+ these swap logs will have names such as:
+
+ cache_swap_log.00
+ cache_swap_log.01
+ cache_swap_log.02
+
+ The numbered extension (which is added automatically)
+ corresponds to the order of the 'cache_dir' lines in this
+ configuration file. If you change the order of the 'cache_dir'
+ lines in this file, these log files will NOT correspond to
+ the correct 'cache_dir' entry (unless you manually rename
+ them). We recommend you do NOT use this option. It is
+ better to keep these log files in each 'cache_dir' directory.
+DOC_END
+
+
+NAME: emulate_httpd_log
+COMMENT: on|off
+TYPE: onoff
+DEFAULT: off
+LOC: Config.onoff.common_log
+DOC_START
+ The Cache can emulate the log file format which many 'httpd'
+ programs use. To disable/enable this emulation, set
+ emulate_httpd_log to 'off' or 'on'. The default
+ is to use the native log format since it includes useful
+ information Squid-specific log analyzers use.
+DOC_END
+
+NAME: log_ip_on_direct
+COMMENT: on|off
+TYPE: onoff
+DEFAULT: on
+LOC: Config.onoff.log_ip_on_direct
+DOC_START
+ Log the destination IP address in the hierarchy log tag when going
+ direct. Earlier Squid versions logged the hostname here. If you
+ prefer the old way set this to off.
+DOC_END
+
+NAME: mime_table
+TYPE: string
+DEFAULT: @DEFAULT_MIME_TABLE@
+LOC: Config.mimeTablePathname
+DOC_START
+ Pathname to Squid's MIME table. You shouldn't need to change
+ this, but the default file contains examples and formatting
+ information if you do.
+DOC_END
+
+
+NAME: log_mime_hdrs
+COMMENT: on|off
+TYPE: onoff
+LOC: Config.onoff.log_mime_hdrs
+DEFAULT: off
+DOC_START
+ The Cache can record both the request and the response MIME
+ headers for each HTTP transaction. The headers are encoded
+ safely and will appear as two bracketed fields at the end of
+ the access log (for either the native or httpd-emulated log
+ formats). To enable this logging set log_mime_hdrs to 'on'.
+DOC_END
+
+
+NAME: useragent_log
+TYPE: string
+LOC: Config.Log.useragent
+DEFAULT: none
+IFDEF: USE_USERAGENT_LOG
+DOC_START
+ Squid will write the User-Agent field from HTTP requests
+ to the filename specified here. By default useragent_log
+ is disabled.
+DOC_END
+
+
+NAME: referer_log referrer_log
+TYPE: string
+LOC: Config.Log.referer
+DEFAULT: none
+IFDEF: USE_REFERER_LOG
+DOC_START
+ Squid will write the Referer field from HTTP requests to the
+ filename specified here. By default referer_log is disabled.
+ Note that "referer" is actually a misspelling of "referrer"
+ however the misspelt version has been accepted into the HTTP RFCs
+ and we accept both.
+DOC_END
+
+
+NAME: pid_filename
+TYPE: string
+DEFAULT: @DEFAULT_PID_FILE@
+LOC: Config.pidFilename
+DOC_START
+ A filename to write the process-id to. To disable, enter "none".
+DOC_END
+
+
+NAME: debug_options
+TYPE: eol
+DEFAULT: ALL,1
+LOC: Config.debugOptions
+DOC_START
+ Logging options are set as section,level where each source file
+ is assigned a unique section. Lower levels result in less
+ output, Full debugging (level 9) can result in a very large
+ log file, so be careful. The magic word "ALL" sets debugging
+ levels for all sections. We recommend normally running with
+ "ALL,1".
+DOC_END
+
+
+NAME: log_fqdn
+COMMENT: on|off
+TYPE: onoff
+DEFAULT: off
+LOC: Config.onoff.log_fqdn
+DOC_START
+ Turn this on if you wish to log fully qualified domain names
+ in the access.log. To do this Squid does a DNS lookup of all
+ IP's connecting to it. This can (in some situations) increase
+ latency, which makes your cache seem slower for interactive
+ browsing.
+DOC_END
+
+
+NAME: client_netmask
+TYPE: address
+LOC: Config.Addrs.client_netmask
+DEFAULT: 255.255.255.255
+DOC_START
+ A netmask for client addresses in logfiles and cachemgr output.
+ Change this to protect the privacy of your cache clients.
+ A netmask of 255.255.255.0 will log all IP's in that range with
+ the last digit set to '0'.
+DOC_END
+
+
+COMMENT_START
+ OPTIONS FOR EXTERNAL SUPPORT PROGRAMS
+ -----------------------------------------------------------------------------
+COMMENT_END
+
+NAME: ftp_user
+TYPE: string
+DEFAULT: Squid@
+LOC: Config.Ftp.anon_user
+DOC_START
+ If you want the anonymous login password to be more informative
+ (and enable the use of picky ftp servers), set this to something
+ reasonable for your domain, like wwwuser@somewhere.net
+
+ The reason why this is domainless by default is the
+ request can be made on the behalf of a user in any domain,
+ depending on how the cache is used.
+ Some ftp server also validate the email address is valid
+ (for example perl.com).
+DOC_END
+
+NAME: ftp_list_width
+TYPE: int
+DEFAULT: 32
+LOC: Config.Ftp.list_width
+DOC_START
+ Sets the width of ftp listings. This should be set to fit in
+ the width of a standard browser. Setting this too small
+ can cut off long filenames when browsing ftp sites.
+DOC_END
+
+NAME: ftp_passive
+TYPE: onoff
+DEFAULT: on
+LOC: Config.Ftp.passive
+DOC_START
+ If your firewall does not allow Squid to use passive
+ connections, turn off this option.
+DOC_END
+
+NAME: ftp_sanitycheck
+TYPE: onoff
+DEFAULT: on
+LOC: Config.Ftp.sanitycheck
+DOC_START
+ For security and data integrity reasons Squid by default performs
+ sanity checks of the addresses of FTP data connections ensure the
+ data connection is to the requested server. If you need to allow
+ FTP connections to servers using another IP address for the data
+ connection turn this off.
+DOC_END
+
+NAME: ftp_telnet_protocol
+TYPE: onoff
+DEFAULT: on
+LOC: Config.Ftp.telnet
+DOC_START
+ The FTP protocol is officially defined to use the telnet protocol
+ as transport channel for the control connection. However, many
+ implementations are broken and does not respect this aspect of
+ the FTP protocol.
+
+ If you have trouble accessing files with ASCII code 255 in the
+ path or similar problems involving this ASCII code you can
+ try setting this directive to off. If that helps, report to the
+ operator of the FTP server in question that their FTP server
+ is broken and does not follow the FTP standard.
+DOC_END
+
+NAME: check_hostnames
+TYPE: onoff
+DEFAULT: on
+LOC: Config.onoff.check_hostnames
+DOC_START
+ For security and stability reasons Squid by default checks
+ hostnames for Internet standard RFC compliance. If you do not want
+ Squid to perform these checks then turn this directive off.
+DOC_END
+
+NAME: allow_underscore
+TYPE: onoff
+DEFAULT: on
+LOC: Config.onoff.allow_underscore
+DOC_START
+ Underscore characters is not strictly allowed in Internet hostnames
+ but nevertheless used by many sites. Set this to off if you want
+ Squid to be strict about the standard.
+DOC_END
+
+NAME: cache_dns_program
+TYPE: string
+IFDEF: USE_DNSSERVERS
+DEFAULT: @DEFAULT_DNSSERVER@
+LOC: Config.Program.dnsserver
+DOC_START
+ Specify the location of the executable for dnslookup process.
+DOC_END
+
+NAME: dns_children
+TYPE: int
+IFDEF: USE_DNSSERVERS
+DEFAULT: 5
+LOC: Config.dnsChildren
+DOC_START
+ The number of processes spawn to service DNS name lookups.
+ For heavily loaded caches on large servers, you should
+ probably increase this value to at least 10. The maximum
+ is 32. The default is 5.
+
+ You must have at least one dnsserver process.
+DOC_END
+
+NAME: dns_retransmit_interval
+TYPE: time_t
+DEFAULT: 5 seconds
+LOC: Config.Timeout.idns_retransmit
+IFDEF: !USE_DNSSERVERS
+DOC_START
+ Initial retransmit interval for DNS queries. The interval is
+ doubled each time all configured DNS servers have been tried.
+
+DOC_END
+
+NAME: dns_timeout
+TYPE: time_t
+DEFAULT: 2 minutes
+LOC: Config.Timeout.idns_query
+IFDEF: !USE_DNSSERVERS
+DOC_START
+ DNS Query timeout. If no response is received to a DNS query
+ within this time all DNS servers for the queried domain
+ are assumed to be unavailable.
+DOC_END
+
+NAME: dns_defnames
+COMMENT: on|off
+TYPE: onoff
+DEFAULT: off
+LOC: Config.onoff.res_defnames
+DOC_START
+ Normally the RES_DEFNAMES resolver option is disabled
+ (see res_init(3)). This prevents caches in a hierarchy
+ from interpreting single-component hostnames locally. To allow
+ Squid to handle single-component names, enable this option.
+DOC_END
+
+NAME: dns_nameservers
+TYPE: wordlist
+DEFAULT: none
+LOC: Config.dns_nameservers
+DOC_START
+ Use this if you want to specify a list of DNS name servers
+ (IP addresses) to use instead of those given in your
+ /etc/resolv.conf file.
+ On Windows platforms, if no value is specified here or in
+ the /etc/resolv.conf file, the list of DNS name servers are
+ taken from the Windows registry, both static and dynamic DHCP
+ configurations are supported.
+
+ Example: dns_nameservers 10.0.0.1 192.172.0.4
+DOC_END
+
+NAME: hosts_file
+TYPE: string
+DEFAULT: @DEFAULT_HOSTS@
+LOC: Config.etcHostsPath
+DOC_START
+ Location of the host-local IP name-address associations
+ database. Most Operating Systems have such a file on different
+ default locations:
+ - Un*X & Linux: /etc/hosts
+ - Windows NT/2000: %SystemRoot%\system32\drivers\etc\hosts
+ (%SystemRoot% value install default is c:\winnt)
+ - Windows XP/2003: %SystemRoot%\system32\drivers\etc\hosts
+ (%SystemRoot% value install default is c:\windows)
+ - Windows 9x/Me: %windir%\hosts
+ (%windir% value is usually c:\windows)
+ - Cygwin: /etc/hosts
+
+ The file contains newline-separated definitions, in the
+ form ip_address_in_dotted_form name [name ...] names are
+ whitespace-separated. Lines beginning with an hash (#)
+ character are comments.
+
+ The file is checked at startup and upon configuration.
+ If set to 'none', it won't be checked.
+ If append_domain is used, that domain will be added to
+ domain-local (i.e. not containing any dot character) host
+ definitions.
+DOC_END
+
+NAME: diskd_program
+TYPE: string
+DEFAULT: @DEFAULT_DISKD@
+LOC: Config.Program.diskd
+DOC_START
+ Specify the location of the diskd executable.
+ Note that this is only useful if you have compiled in
+ diskd as one of the store io modules.
+DOC_END
+
+NAME: unlinkd_program
+IFDEF: USE_UNLINKD
+TYPE: string
+DEFAULT: @DEFAULT_UNLINKD@
+LOC: Config.Program.unlinkd
+DOC_START
+ Specify the location of the executable for file deletion process.
+DOC_END
+
+NAME: pinger_program
+TYPE: string
+DEFAULT: @DEFAULT_PINGER@
+LOC: Config.Program.pinger
+IFDEF: USE_ICMP
+DOC_START
+ Specify the location of the executable for the pinger process.
+DOC_END
+
+
+NAME: url_rewrite_program redirect_program
+TYPE: programline
+LOC: Config.Program.url_rewrite.command
+DEFAULT: none
+DOC_START
+ Specify the location of the executable for the URL rewriter.
+ Since they can perform almost any function there isn't one included.
+
+ For each requested URL rewriter will receive on line with the format
+
+ URL client_ip "/" fqdn user method urlgroup
+
+ And the rewriter may return a rewritten URL. The other components of
+ the request line does not need to be returned (ignored if they are).
+
+ The rewriter can also indicate that a client-side redirect should
+ be performed to the new URL. This is done by prefixing the returned
+ URL with "301:" (moved permanently) or 302: (moved temporarily).
+
+ It can also return a "urlgroup" that can subsequently be matched
+ in cache_peer_access and similar ACL driven rules. An urlgroup is
+ returned by prefixing the returned url with "!urlgroup!"
+
+ By default, a URL rewriter is not used.
+DOC_END
+
+NAME: url_rewrite_children redirect_children
+TYPE: int
+DEFAULT: 5
+LOC: Config.Program.url_rewrite.children
+DOC_START
+ The number of redirector processes to spawn. If you start
+ too few Squid will have to wait for them to process a backlog of
+ URLs, slowing it down. If you start too many they will use RAM
+ and other system resources.
+DOC_END
+
+NAME: url_rewrite_concurrency redirect_concurrency
+TYPE: int
+DEFAULT: 0
+LOC: Config.Program.url_rewrite.concurrency
+DOC_START
+ The number of requests each redirector helper can handle in
+ parallel. Defaults to 0 which indicates that the redirector
+ is a old-style singlethreaded redirector.
+DOC_END
+
+NAME: url_rewrite_host_header redirect_rewrites_host_header
+TYPE: onoff
+DEFAULT: on
+LOC: Config.onoff.redir_rewrites_host
+DOC_START
+ By default Squid rewrites any Host: header in redirected
+ requests. If you are running an accelerator this may
+ not be a wanted effect of a redirector.
+
+ WARNING: Entries are cached on the result of the URL rewriting
+ process, so be careful if you have domain-virtual hosts.
+DOC_END
+
+NAME: url_rewrite_access redirector_access
+TYPE: acl_access
+DEFAULT: none
+LOC: Config.accessList.url_rewrite
+DOC_START
+ If defined, this access list specifies which requests are
+ sent to the redirector processes. By default all requests
+ are sent.
+DOC_END
+
+NAME: location_rewrite_program
+TYPE: programline
+LOC: Config.Program.location_rewrite.command
+DEFAULT: none
+DOC_START
+ Specify the location of the executable for the Location rewriter,
+ used to rewrite server generated redirects. Usually used in
+ conjunction with a url_rewrite_program
+
+ For each Location header received the location rewriter will receive
+ one line with the format:
+
+ location URL requested URL urlgroup
+
+ And the rewriter may return a rewritten Location URL or a blank line.
+ The other components of the request line does not need to be returned
+ (ignored if they are).
+
+ By default, a Location rewriter is not used.
+DOC_END
+
+NAME: location_rewrite_children
+TYPE: int
+DEFAULT: 5
+LOC: Config.Program.location_rewrite.children
+DOC_START
+ The number of location rewriting processes to spawn. If you start
+ too few Squid will have to wait for them to process a backlog of
+ URLs, slowing it down. If you start too many they will use RAM
+ and other system resources.
+DOC_END
+
+NAME: location_rewrite_concurrency
+TYPE: int
+DEFAULT: 0
+LOC: Config.Program.location_rewrite.concurrency
+DOC_START
+ The number of requests each Location rewriter helper can handle in
+ parallel. Defaults to 0 which indicates that the helper
+ is a old-style singlethreaded helper.
+DOC_END
+
+NAME: location_rewrite_access
+TYPE: acl_access
+DEFAULT: none
+LOC: Config.accessList.location_rewrite
+DOC_START
+ If defined, this access list specifies which requests are
+ sent to the location rewriting processes. By default all Location
+ headers are sent.
+DOC_END
+
+
+NAME: auth_param
+TYPE: authparam
+LOC: Config.authConfig
+DEFAULT: none
+DOC_START
+ This is used to define parameters for the various authentication
+ schemes supported by Squid.
+
+ format: auth_param scheme parameter [setting]
+
+ The order in which authentication schemes are presented to the client is
+ dependent on the order the scheme first appears in config file. IE
+ has a bug (it's not RFC 2617 compliant) in that it will use the basic
+ scheme if basic is the first entry presented, even if more secure
+ schemes are presented. For now use the order in the recommended
+ settings section below. If other browsers have difficulties (don't
+ recognize the schemes offered even if you are using basic) either
+ put basic first, or disable the other schemes (by commenting out their
+ program entry).
+
+ Once an authentication scheme is fully configured, it can only be
+ shutdown by shutting squid down and restarting. Changes can be made on
+ the fly and activated with a reconfigure. I.E. You can change to a
+ different helper, but not unconfigure the helper completely.
+
+ Please note that while this directive defines how Squid processes
+ authentication it does not automatically activate authentication.
+ To use authentication you must in addition make use of ACLs based
+ on login name in http_access (proxy_auth, proxy_auth_regex or
+ external with %LOGIN used in the format tag). The browser will be
+ challenged for authentication on the first such acl encountered
+ in http_access processing and will also be re-challenged for new
+ login credentials if the request is being denied by a proxy_auth
+ type acl.
+
+ WARNING: authentication can't be used in a transparently intercepting
+ proxy as the client then thinks it is talking to an origin server and
+ not the proxy. This is a limitation of bending the TCP/IP protocol to
+ transparently intercepting port 80, not a limitation in Squid.
+
+ === Parameters for the basic scheme follow. ===
+
+ "program" cmdline
+ Specify the command for the external authenticator. Such a program
+ reads a line containing "username password" and replies "OK" or
+ "ERR" in an endless loop. "ERR" responses may optionally be followed
+ by a error description available as %m in the returned error page.
+
+ By default, the basic authentication scheme is not used unless a
+ program is specified.
+
+ If you want to use the traditional proxy authentication, jump over to
+ the helpers/basic_auth/NCSA directory and type:
+ % make
+ % make install
+
+ Then, set this line to something like
+
+ auth_param basic program @DEFAULT_PREFIX@/libexec/ncsa_auth @DEFAULT_PREFIX@/etc/passwd
+
+ "children" numberofchildren
+ The number of authenticator processes to spawn. If you start too few
+ squid will have to wait for them to process a backlog of credential
+ verifications, slowing it down. When credential verifications are
+ done via a (slow) network you are likely to need lots of
+ authenticator processes.
+ auth_param basic children 5
+
+ "concurrency" numberofconcurrentrequests
+ The number of concurrent requests/channels the helper supports.
+ Changes the protocol used to include a channel number first on
+ the request/response line, allowing multiple requests to be sent
+ to the same helper in parallell without wating for the response.
+ Must not be set unless it's known the helper supports this.
+
+ "realm" realmstring
+ Specifies the realm name which is to be reported to the client for
+ the basic proxy authentication scheme (part of the text the user
+ will see when prompted their username and password).
+ auth_param basic realm Squid proxy-caching web server
+
+ "credentialsttl" timetolive
+ Specifies how long squid assumes an externally validated
+ username:password pair is valid for - in other words how often the
+ helper program is called for that user. Set this low to force
+ revalidation with short lived passwords. Note that setting this high
+ does not impact your susceptibility to replay attacks unless you are
+ using an one-time password system (such as SecureID). If you are using
+ such a system, you will be vulnerable to replay attacks unless you
+ also use the max_user_ip ACL in an http_access rule.
+ auth_param basic credentialsttl 2 hours
+
+ "casesensitive" on|off
+ Specifies if usernames are case sensitive. Most user databases are
+ case insensitive allowing the same username to be spelled using both
+ lower and upper case letters, but some are case sensitive. This
+ makes a big difference for user_max_ip ACL processing and similar.
+ auth_param basic casesensitive off
+
+ "blankpassword" on|off
+ Specifies if blank passwords should be supported. Defaults to off
+ as there is multiple authentication backends which handles blank
+ passwords as "guest" access.
+
+ === Parameters for the digest scheme follow ===
+
+ "program" cmdline
+ Specify the command for the external authenticator. Such a program
+ reads a line containing "username":"realm" and replies with the
+ appropriate H(A1) value base64 encoded or ERR if the user (or his H(A1)
+ hash) does not exists. See RFC 2616 for the definition of H(A1).
+ "ERR" responses may optionally be followed by a error description
+ available as %m in the returned error page.
+
+ By default, the digest authentication scheme is not used unless a
+ program is specified.
+
+ If you want to use a digest authenticator, jump over to the
+ helpers/digest_auth/ directory and choose the authenticator to use.
+ It it's directory type
+ % make
+ % make install
+
+ Then, set this line to something like
+
+ auth_param digest program @DEFAULT_PREFIX@/libexec/digest_auth_pw @DEFAULT_PREFIX@/etc/digpass
+
+
+ "children" numberofchildren
+ The number of authenticator processes to spawn. If you start too few
+ squid will have to wait for them to process a backlog of credential
+ verifications, slowing it down. When credential verifications are
+ done via a (slow) network you are likely to need lots of
+ authenticator processes.
+ auth_param digest children 5
+
+ "concurrency" numberofconcurrentrequests
+ The number of concurrent requests/channels the helper supports.
+ Changes the protocol used to include a channel number first on
+ the request/response line, allowing multiple requests to be sent
+ to the same helper in parallell without wating for the response.
+ Must not be set unless it's known the helper supports this.
+
+ "realm" realmstring
+ Specifies the realm name which is to be reported to the client for the
+ digest proxy authentication scheme (part of the text the user will see
+ when prompted their username and password).
+ auth_param digest realm Squid proxy-caching web server
+
+ "nonce_garbage_interval" timeinterval
+ Specifies the interval that nonces that have been issued to clients are
+ checked for validity.
+ auth_param digest nonce_garbage_interval 5 minutes
+
+ "nonce_max_duration" timeinterval
+ Specifies the maximum length of time a given nonce will be valid for.
+ auth_param digest nonce_max_duration 30 minutes
+
+ "nonce_max_count" number
+ Specifies the maximum number of times a given nonce can be used.
+ auth_param digest nonce_max_count 50
+
+ "nonce_strictness" on|off
+ Determines if squid requires strict increment-by-1 behavior for nonce
+ counts, or just incrementing (off - for use when useragents generate
+ nonce counts that occasionally miss 1 (ie, 1,2,4,6)).
+ auth_param digest nonce_strictness off
+
+ "check_nonce_count" on|off
+ This directive if set to off can disable the nonce count check
+ completely to work around buggy digest qop implementations in certain
+ mainstream browser versions. Default on to check the nonce count to
+ protect from authentication replay attacks.
+ auth_param digest check_nonce_count on
+
+ "post_workaround" on|off
+ This is a workaround to certain buggy browsers who sends an incorrect
+ request digest in POST requests when reusing the same nonce as acquired
+ earlier in response to a GET request.
+ auth_param digest post_workaround off
+
+ === NTLM scheme options follow ===
+
+ "program" cmdline
+ Specify the command for the external NTLM authenticator. Such a
+ program participates in the NTLMSSP exchanges between Squid and the
+ client and reads commands according to the Squid NTLMSSP helper
+ protocol. See helpers/ntlm_auth/ for details. Recommended ntlm
+ authenticator is ntlm_auth from Samba-3.X, but a number of other
+ ntlm authenticators is available.
+
+ By default, the ntlm authentication scheme is not used unless a
+ program is specified.
+
+ auth_param ntlm program /path/to/samba/bin/ntlm_auth --helper-protocol=squid-2.5-ntlmssp
+
+ "children" numberofchildren
+ The number of authenticator processes to spawn. If you start too few
+ squid will have to wait for them to process a backlog of credential
+ verifications, slowing it down. When credential verifications are
+ done via a (slow) network you are likely to need lots of
+ authenticator processes.
+ auth_param ntlm children 5
+
+ "keep_alive" on|off
+ This option enables the use of keep-alive on the initial
+ authentication request. It has been reported some versions of MSIE
+ have problems if this is enabled, but performance will be increased
+ if enabled.
+
+ auth_param ntlm keep_alive on
+
+ === Negotiate scheme options follow ===
+
+ "program" cmdline
+ Specify the command for the external Negotiate authenticator. Such a
+ program participates in the SPNEGO exchanges between Squid and the
+ client and reads commands according to the Squid ntlmssp helper
+ protocol. See helpers/ntlm_auth/ for details. Recommended SPNEGO
+ authenticator is ntlm_auth from Samba-4.X.
+
+ By default, the Negotiate authentication scheme is not used unless a
+ program is specified.
+
+ auth_param negotiate program /path/to/samba/bin/ntlm_auth --helper-protocol=gss-spnego
+
+ "children" numberofchildren
+ The number of authenticator processes to spawn. If you start too few
+ squid will have to wait for them to process a backlog of credential
+ verifications, slowing it down. When credential verifications are
+ done via a (slow) network you are likely to need lots of
+ authenticator processes.
+ auth_param negotiate children 5
+
+ "keep_alive" on|off
+ If you experience problems with PUT/POST requests when using the
+ Negotiate authentication scheme then you can try setting this to
+ off. This will cause Squid to forcibly close the connection on
+ the initial requests where the browser asks which schemes are
+ supported by the proxy.
+
+ auth_param negotiate keep_alive on
+
+NOCOMMENT_START
+#Recommended minimum configuration per scheme:
+#auth_param negotiate program
+#auth_param negotiate children 5
+#auth_param negotiate keep_alive on
+#auth_param ntlm program
+#auth_param ntlm children 5
+#auth_param ntlm keep_alive on
+#auth_param digest program
+#auth_param digest children 5
+#auth_param digest realm Squid proxy-caching web server
+#auth_param digest nonce_garbage_interval 5 minutes
+#auth_param digest nonce_max_duration 30 minutes
+#auth_param digest nonce_max_count 50
+#auth_param basic program
+#auth_param basic children 5
+#auth_param basic realm Squid proxy-caching web server
+#auth_param basic credentialsttl 2 hours
+#auth_param basic casesensitive off
+NOCOMMENT_END
+DOC_END
+
+NAME: authenticate_cache_garbage_interval
+TYPE: time_t
+DEFAULT: 1 hour
+LOC: Config.authenticateGCInterval
+DOC_START
+ The time period between garbage collection across the username cache.
+ This is a tradeoff between memory utilization (long intervals - say
+ 2 days) and CPU (short intervals - say 1 minute). Only change if you
+ have good reason to.
+DOC_END
+
+NAME: authenticate_ttl
+TYPE: time_t
+DEFAULT: 1 hour
+LOC: Config.authenticateTTL
+DOC_START
+ The time a user & their credentials stay in the logged in user cache
+ since their last request. When the garbage interval passes, all user
+ credentials that have passed their TTL are removed from memory.
+DOC_END
+
+NAME: authenticate_ip_ttl
+TYPE: time_t
+LOC: Config.authenticateIpTTL
+DEFAULT: 0 seconds
+DOC_START
+ If you use proxy authentication and the 'max_user_ip' ACL, this
+ directive controls how long Squid remembers the IP addresses
+ associated with each user. Use a small value (e.g., 60 seconds) if
+ your users might change addresses quickly, as is the case with
+ dialups. You might be safe using a larger value (e.g., 2 hours) in a
+ corporate LAN environment with relatively static address assignments.
+DOC_END
+
+NAME: external_acl_type
+TYPE: externalAclHelper
+LOC: Config.externalAclHelperList
+DEFAULT: none
+DOC_START
+ This option defines external acl classes using a helper program to
+ look up the status
+
+ external_acl_type name [options] FORMAT.. /path/to/helper [helper arguments..]
+
+ Options:
+
+ ttl=n TTL in seconds for cached results (defaults to 3600
+ for 1 hour)
+ negative_ttl=n
+ TTL for cached negative lookups (default same
+ as ttl)
+ children=n number of processes spawn to service external acl
+ lookups of this type.
+ concurrency=n concurrency level per process. Use 0 for simple helpers
+ who can only process a single request at a time.
+ Note: see compatibility note below
+ cache=n result cache size, 0 is unbounded (default)
+ grace= Percentage remaining of TTL where a refresh of a
+ cached entry should be initiated without needing to
+ wait for a new reply. (default 0 for no grace period)
+ protocol=2.5 Compatibility mode for Squid-2.5 external acl helpers
+
+ FORMAT specifications
+
+ %LOGIN Authenticated user login name
+ %IDENT Ident user name
+ %SRC Client IP
+ %SRCPORT Client source port
+ %DST Requested host
+ %PROTO Requested protocol
+ %PORT Requested port
+ %METHOD Request method
+ %MYADDR Squid interface address
+ %MYPORT Squid http_port number
+ %PATH Requested URL-path (including query-string if any)
+ %USER_CERT SSL User certificate in PEM format
+ %USER_CERTCHAIN SSL User certificate chain in PEM format
+ %USER_CERT_xx SSL User certificate subject attribute xx
+ %USER_CA_xx SSL User certificate issuer attribute xx
+ %{Header} HTTP request header
+ %{Hdr:member} HTTP request header list member
+ %{Hdr:;member}
+ HTTP request header list member using ; as
+ list separator. ; can be any non-alphanumeric
+ character.
+ %ACL The ACL name
+ %DATA The ACL arguments. If not used then any arguments
+ is automatically added at the end
+
+ In addition, any string specified in the referencing acl will
+ also be included in the helper request line, after the specified
+ formats (see the "acl external" directive)
+
+ The helper receives lines per the above format specification,
+ and returns lines starting with OK or ERR indicating the validity
+ of the request and optionally followed by additional keywords with
+ more details.
+
+ General result syntax:
+
+ OK/ERR keyword=value ...
+
+ Defined keywords:
+
+ user= The users name (login also understood)
+ password= The users password (for PROXYPASS login= cache_peer)
+ message= Error message or similar used as %o in error messages
+ (error also understood)
+ log= String to be logged in access.log. Available as
+ %ea in logformat specifications
+
+ Keyword values need to be enclosed in quotes if they may contain
+ whitespace, or the whitespace escaped using \. Any quotes or \
+ characters within the keyword value must be \ escaped.
+
+ If protocol=3.0 then URL escaping of the strings is used instead
+ of the above described quoting format.
+
+ Compatibility Note: The children= option was named concurrency= in
+ Squid-2.5.STABLE3 and earlier, and was accepted as an alias for the
+ duration of the Squid-2.5 releases to keep compatibility. However,
+ the meaning of concurrency= option has changed in Squid-2.6 to match
+ that of Squid-3 and the old syntax no longer works.
+DOC_END
+
+COMMENT_START
+ OPTIONS FOR TUNING THE CACHE
+ -----------------------------------------------------------------------------
+COMMENT_END
+
+NAME: wais_relay_host
+TYPE: string
+DEFAULT: none
+LOC: Config.Wais.relayHost
+DOC_NONE
+
+NAME: wais_relay_port
+TYPE: ushort
+DEFAULT: 0
+LOC: Config.Wais.relayPort
+DOC_START
+ Relay WAIS request to host (1st arg) at port (2 arg).
+DOC_END
+
+
+NAME: request_header_max_size
+COMMENT: (KB)
+TYPE: b_size_t
+DEFAULT: 20 KB
+LOC: Config.maxRequestHeaderSize
+DOC_START
+ This specifies the maximum size for HTTP headers in a request.
+ Request headers are usually relatively small (about 512 bytes).
+ Placing a limit on the request header size will catch certain
+ bugs (for example with persistent connections) and possibly
+ buffer-overflow or denial-of-service attacks.
+DOC_END
+
+NAME: request_body_max_size
+COMMENT: (KB)
+TYPE: b_size_t
+DEFAULT: 0 KB
+LOC: Config.maxRequestBodySize
+DOC_START
+ This specifies the maximum size for an HTTP request body.
+ In other words, the maximum size of a PUT/POST request.
+ A user who attempts to send a request with a body larger
+ than this limit receives an "Invalid Request" error message.
+ If you set this parameter to a zero (the default), there will
+ be no limit imposed.
+DOC_END
+
+NAME: refresh_pattern
+TYPE: refreshpattern
+LOC: Config.Refresh
+DEFAULT: none
+DOC_START
+ usage: refresh_pattern [-i] regex min percent max [options]
+
+ By default, regular expressions are CASE-SENSITIVE. To make
+ them case-insensitive, use the -i option.
+
+ 'Min' is the time (in minutes) an object without an explicit
+ expiry time should be considered fresh. The recommended
+ value is 0, any higher values may cause dynamic applications
+ to be erroneously cached unless the application designer
+ has taken the appropriate actions.
+
+ 'Percent' is a percentage of the objects age (time since last
+ modification age) an object without explicit expiry time
+ will be considered fresh.
+
+ 'Max' is an upper limit on how long objects without an explicit
+ expiry time will be considered fresh.
+
+ options: override-expire
+ override-lastmod
+ reload-into-ims
+ ignore-reload
+ ignore-no-cache
+ ignore-private
+ ignore-auth
+
+ override-expire enforces min age even if the server
+ sent a Expires: header. Doing this VIOLATES the HTTP
+ standard. Enabling this feature could make you liable
+ for problems which it causes.
+
+ override-lastmod enforces min age even on objects
+ that were modified recently.
+
+ reload-into-ims changes client no-cache or ``reload''
+ to If-Modified-Since requests. Doing this VIOLATES the
+ HTTP standard. Enabling this feature could make you
+ liable for problems which it causes.
+
+ ignore-reload ignores a client no-cache or ``reload''
+ header. Doing this VIOLATES the HTTP standard. Enabling
+ this feature could make you liable for problems which
+ it causes.
+
+ ignore-no-cache ignores any ``Pragma: no-cache'' and
+ ``Cache-control: no-cache'' headers received from a server.
+ The HTTP RFC never allows the use of this (Pragma) header
+ from a server, only a client, though plenty of servers
+ send it anyway.
+
+ ignore-private ignores any ``Cache-control: private''
+ headers received from a server. Doing this VIOLATES
+ the HTTP standard. Enabling this feature could make you
+ liable for problems which it causes.
+
+ ignore-auth caches responses to requests with authorization,
+ irrespective of ``Cache-control'' headers received from
+ a server. Doing this VIOLATES the HTTP standard. Enabling
+ this feature could make you liable for problems which
+ it causes.
+
+ Basically a cached object is:
+
+ FRESH if expires < now, else STALE
+ STALE if age > max
+ FRESH if lm-factor < percent, else STALE
+ FRESH if age < min
+ else STALE
+
+ The refresh_pattern lines are checked in the order listed here.
+ The first entry which matches is used. If none of the entries
+ match the default will be used.
+
+ Note, you must uncomment all the default lines if you want
+ to change one. The default setting is only active if none is
+ used.
+
+Suggested default:
+NOCOMMENT_START
+refresh_pattern ^ftp: 1440 20% 10080
+refresh_pattern ^gopher: 1440 0% 1440
+refresh_pattern . 0 20% 4320
+NOCOMMENT_END
+DOC_END
+
+NAME: quick_abort_min
+COMMENT: (KB)
+TYPE: kb_size_t
+DEFAULT: 16 KB
+LOC: Config.quickAbort.min
+DOC_NONE
+
+NAME: quick_abort_max
+COMMENT: (KB)
+TYPE: kb_size_t
+DEFAULT: 16 KB
+LOC: Config.quickAbort.max
+DOC_NONE
+
+NAME: quick_abort_pct
+COMMENT: (percent)
+TYPE: int
+DEFAULT: 95
+LOC: Config.quickAbort.pct
+DOC_START
+ The cache by default continues downloading aborted requests
+ which are almost completed (less than 16 KB remaining). This
+ may be undesirable on slow (e.g. SLIP) links and/or very busy
+ caches. Impatient users may tie up file descriptors and
+ bandwidth by repeatedly requesting and immediately aborting
+ downloads.
+
+ When the user aborts a request, Squid will check the
+ quick_abort values to the amount of data transfered until
+ then.
+
+ If the transfer has less than 'quick_abort_min' KB remaining,
+ it will finish the retrieval.
+
+ If the transfer has more than 'quick_abort_max' KB remaining,
+ it will abort the retrieval.
+
+ If more than 'quick_abort_pct' of the transfer has completed,
+ it will finish the retrieval.
+
+ If you do not want any retrieval to continue after the client
+ has aborted, set both 'quick_abort_min' and 'quick_abort_max'
+ to '0 KB'.
+
+ If you want retrievals to always continue if they are being
+ cached set 'quick_abort_min' to '-1 KB'.
+DOC_END
+
+NAME: read_ahead_gap
+COMMENT: buffer-size
+TYPE: b_size_t
+LOC: Config.readAheadGap
+DEFAULT: 16 KB
+DOC_START
+ The amount of data the cache will buffer ahead of what has been
+ sent to the client when retrieving an object from another server.
+DOC_END
+
+NAME: negative_ttl
+COMMENT: time-units
+TYPE: time_t
+LOC: Config.negativeTtl
+DEFAULT: 5 minutes
+DOC_START
+ Time-to-Live (TTL) for failed requests. Certain types of
+ failures (such as "connection refused" and "404 Not Found") are
+ negatively-cached for a configurable amount of time. The
+ default is 5 minutes. Note that this is different from
+ negative caching of DNS lookups.
+DOC_END
+
+
+NAME: positive_dns_ttl
+COMMENT: time-units
+TYPE: time_t
+LOC: Config.positiveDnsTtl
+DEFAULT: 6 hours
+DOC_START
+ Upper limit on how long Squid will cache positive DNS responses.
+ Default is 6 hours (360 minutes). This directive must be set
+ larger than negative_dns_ttl.
+DOC_END
+
+
+NAME: negative_dns_ttl
+COMMENT: time-units
+TYPE: time_t
+LOC: Config.negativeDnsTtl
+DEFAULT: 1 minute
+DOC_START
+ Time-to-Live (TTL) for negative caching of failed DNS lookups.
+ This also makes sets the lower cache limit on positive lookups.
+ Minimum value is 1 second, and it is not recommendable to go
+ much below 10 seconds.
+DOC_END
+
+NAME: range_offset_limit
+COMMENT: (bytes)
+TYPE: b_size_t
+LOC: Config.rangeOffsetLimit
+DEFAULT: 0 KB
+DOC_START
+ Sets a upper limit on how far into the the file a Range request
+ may be to cause Squid to prefetch the whole file. If beyond this
+ limit Squid forwards the Range request as it is and the result
+ is NOT cached.
+
+ This is to stop a far ahead range request (lets say start at 17MB)
+ from making Squid fetch the whole object up to that point before
+ sending anything to the client.
+
+ A value of -1 causes Squid to always fetch the object from the
+ beginning so it may cache the result. (2.0 style)
+
+ A value of 0 causes Squid to never fetch more than the
+ client requested. (default)
+DOC_END
+
+NAME: collapsed_forwarding
+COMMENT: (on|off)
+TYPE: onoff
+LOC: Config.onoff.collapsed_forwarding
+DEFAULT: off
+DOC_START
+ This option enables multiple requests for the same URI to be
+ processed as one request. Normally disabled to avoid increased
+ latency on dynamic content, but there can be benefit from enabling
+ this in accelerator setups where the web servers are the bottleneck
+ and reliable and returns mostly cacheable information.
+DOC_END
+
+NAME: refresh_stale_hit
+COMMENT: (time)
+TYPE: time_t
+DEFAULT: 0 seconds
+LOC: Config.refresh_stale_window
+DOC_START
+ This option changes the refresh algorithm to allow concurrent
+ requests while an object is being refreshed to be processed as
+ cache hits if the object expired less than X seconds ago. Default
+ is 0 to disable this feature. This option is mostly interesting
+ in accelerator setups where a few objects is accessed very
+ frequently.
+DOC_END
+
+COMMENT_START
+ TIMEOUTS
+ -----------------------------------------------------------------------------
+COMMENT_END
+
+NAME: forward_timeout
+COMMENT: time-units
+TYPE: time_t
+LOC: Config.Timeout.forward
+DEFAULT: 4 minutes
+DOC_START
+ This parameter specifies how long Squid should at most attempt in
+ finding a forwarding path for the request before giving up.
+DOC_END
+
+NAME: connect_timeout
+COMMENT: time-units
+TYPE: time_t
+LOC: Config.Timeout.connect
+DEFAULT: 1 minute
+DOC_START
+ This parameter specifies how long to wait for the TCP connect to
+ the requested server or peer to complete before Squid should
+ attempt to find another path where to forward the request.
+DOC_END
+
+NAME: peer_connect_timeout
+COMMENT: time-units
+TYPE: time_t
+LOC: Config.Timeout.peer_connect
+DEFAULT: 30 seconds
+DOC_START
+ This parameter specifies how long to wait for a pending TCP
+ connection to a peer cache. The default is 30 seconds. You
+ may also set different timeout values for individual neighbors
+ with the 'connect-timeout' option on a 'cache_peer' line.
+DOC_END
+
+NAME: read_timeout
+COMMENT: time-units
+TYPE: time_t
+LOC: Config.Timeout.read
+DEFAULT: 15 minutes
+DOC_START
+ The read_timeout is applied on server-side connections. After
+ each successful read(), the timeout will be extended by this
+ amount. If no data is read again after this amount of time,
+ the request is aborted and logged with ERR_READ_TIMEOUT. The
+ default is 15 minutes.
+DOC_END
+
+
+NAME: request_timeout
+TYPE: time_t
+LOC: Config.Timeout.request
+DEFAULT: 5 minutes
+DOC_START
+ How long to wait for an HTTP request after initial
+ connection establishment.
+DOC_END
+
+
+NAME: persistent_request_timeout
+TYPE: time_t
+LOC: Config.Timeout.persistent_request
+DEFAULT: 1 minute
+DOC_START
+ How long to wait for the next HTTP request on a persistent
+ connection after the previous request completes.
+DOC_END
+
+
+NAME: client_lifetime
+COMMENT: time-units
+TYPE: time_t
+LOC: Config.Timeout.lifetime
+DEFAULT: 1 day
+DOC_START
+ The maximum amount of time a client (browser) is allowed to
+ remain connected to the cache process. This protects the Cache
+ from having a lot of sockets (and hence file descriptors) tied up
+ in a CLOSE_WAIT state from remote clients that go away without
+ properly shutting down (either because of a network failure or
+ because of a poor client implementation). The default is one
+ day, 1440 minutes.
+
+ NOTE: The default value is intended to be much larger than any
+ client would ever need to be connected to your cache. You
+ should probably change client_lifetime only as a last resort.
+ If you seem to have many client connections tying up
+ filedescriptors, we recommend first tuning the read_timeout,
+ request_timeout, persistent_request_timeout and quick_abort values.
+DOC_END
+
+NAME: half_closed_clients
+TYPE: onoff
+LOC: Config.onoff.half_closed_clients
+DEFAULT: on
+DOC_START
+ Some clients may shutdown the sending side of their TCP
+ connections, while leaving their receiving sides open. Sometimes,
+ Squid can not tell the difference between a half-closed and a
+ fully-closed TCP connection. By default, half-closed client
+ connections are kept open until a read(2) or write(2) on the
+ socket returns an error. Change this option to 'off' and Squid
+ will immediately close client connections when read(2) returns
+ "no more data to read."
+DOC_END
+
+NAME: pconn_timeout
+TYPE: time_t
+LOC: Config.Timeout.pconn
+DEFAULT: 120 seconds
+DOC_START
+ Timeout for idle persistent connections to servers and other
+ proxies.
+DOC_END
+
+NAME: ident_timeout
+TYPE: time_t
+IFDEF: USE_IDENT
+LOC: Config.Timeout.ident
+DEFAULT: 10 seconds
+DOC_START
+ Maximum time to wait for IDENT lookups to complete.
+
+ If this is too high, and you enabled IDENT lookups from untrusted
+ users, you might be susceptible to denial-of-service by having
+ many ident requests going at once.
+DOC_END
+
+
+NAME: shutdown_lifetime
+COMMENT: time-units
+TYPE: time_t
+LOC: Config.shutdownLifetime
+DEFAULT: 30 seconds
+DOC_START
+ When SIGTERM or SIGHUP is received, the cache is put into
+ "shutdown pending" mode until all active sockets are closed.
+ This value is the lifetime to set for all open descriptors
+ during shutdown mode. Any active clients after this many
+ seconds will receive a 'timeout' message.
+DOC_END
+
+COMMENT_START
+ ACCESS CONTROLS
+ -----------------------------------------------------------------------------
+COMMENT_END
+
+NAME: acl
+TYPE: acl
+LOC: Config.aclList
+DEFAULT: none
+DOC_START
+ Defining an Access List
+
+ acl aclname acltype string1 ...
+ acl aclname acltype "file" ...
+
+ when using "file", the file should contain one item per line
+
+ acltype is one of the types described below
+
+ By default, regular expressions are CASE-SENSITIVE. To make
+ them case-insensitive, use the -i option.
+
+ acl aclname src ip-address/netmask ... (clients IP address)
+ acl aclname src addr1-addr2/netmask ... (range of addresses)
+ acl aclname dst ip-address/netmask ... (URL host's IP address)
+ acl aclname myip ip-address/netmask ... (local socket IP address)
+
+ acl aclname arp mac-address ... (xx:xx:xx:xx:xx:xx notation)
+ # The arp ACL requires the special configure option --enable-arp-acl.
+ # Furthermore, the arp ACL code is not portable to all operating systems.
+ # It works on Linux, Solaris, FreeBSD and some other *BSD variants.
+ #
+ # NOTE: Squid can only determine the MAC address for clients that are on
+ # the same subnet. If the client is on a different subnet, then Squid cannot
+ # find out its MAC address.
+
+ acl aclname srcdomain .foo.com ... # reverse lookup, client IP
+ acl aclname dstdomain .foo.com ... # Destination server from URL
+ acl aclname srcdom_regex [-i] xxx ... # regex matching client name
+ acl aclname dstdom_regex [-i] xxx ... # regex matching server
+ # For dstdomain and dstdom_regex a reverse lookup is tried if a IP
+ # based URL is used and no match is found. The name "none" is used
+ # if the reverse lookup fails.
+
+ acl aclname time [day-abbrevs] [h1:m1-h2:m2]
+ day-abbrevs:
+ S - Sunday
+ M - Monday
+ T - Tuesday
+ W - Wednesday
+ H - Thursday
+ F - Friday
+ A - Saturday
+ h1:m1 must be less than h2:m2
+ acl aclname url_regex [-i] ^http:// ... # regex matching on whole URL
+ acl aclname urlpath_regex [-i] \.gif$ ... # regex matching on URL path
+ acl aclname urllogin [-i] [^a-zA-Z0-9] ... # regex matching on URL login field
+ acl aclname port 80 70 21 ...
+ acl aclname port 0-1024 ... # ranges allowed
+ acl aclname myport 3128 ... # (local socket TCP port)
+ acl aclname proto HTTP FTP ...
+ acl aclname method GET POST ...
+ acl aclname browser [-i] regexp ...
+ # pattern match on User-Agent header (see also req_header below)
+ acl aclname referer_regex [-i] regexp ...
+ # pattern match on Referer header
+ # Referer is highly unreliable, so use with care
+ acl aclname ident username ...
+ acl aclname ident_regex [-i] pattern ...
+ # string match on ident output.
+ # use REQUIRED to accept any non-null ident.
+ acl aclname src_as number ...
+ acl aclname dst_as number ...
+ # Except for access control, AS numbers can be used for
+ # routing of requests to specific caches. Here's an
+ # example for routing all requests for AS#1241 and only
+ # those to mycache.mydomain.net:
+ # acl asexample dst_as 1241
+ # cache_peer_access mycache.mydomain.net allow asexample
+ # cache_peer_access mycache_mydomain.net deny all
+
+ acl aclname proxy_auth username ...
+ acl aclname proxy_auth_regex [-i] pattern ...
+ # list of valid usernames
+ # use REQUIRED to accept any valid username.
+ #
+ # NOTE: when a Proxy-Authentication header is sent but it is not
+ # needed during ACL checking the username is NOT logged
+ # in access.log.
+ #
+ # NOTE: proxy_auth requires a EXTERNAL authentication program
+ # to check username/password combinations (see
+ # auth_param directive).
+ #
+ # WARNING: proxy_auth can't be used in a transparent proxy. It
+ # collides with any authentication done by origin servers. It may
+ # seem like it works at first, but it doesn't.
+
+ acl aclname snmp_community string ...
+ # A community string to limit access to your SNMP Agent
+ # Example:
+ #
+ # acl snmppublic snmp_community public
+
+ acl aclname maxconn number
+ # This will be matched when the client's IP address has
+ # more than HTTP connections established.
+
+ acl aclname max_user_ip [-s] number
+ # This will be matched when the user attempts to log in from more
+ # than different ip addresses. The authenticate_ip_ttl
+ # parameter controls the timeout on the ip entries.
+ # If -s is specified the limit is strict, denying browsing
+ # from any further IP addresses until the ttl has expired. Without
+ # -s Squid will just annoy the user by "randomly" denying requests.
+ # (the counter is reset each time the limit is reached and a
+ # request is denied)
+ # NOTE: in acceleration mode or where there is mesh of child proxies,
+ # clients may appear to come from multiple addresses if they are
+ # going through proxy farms, so a limit of 1 may cause user problems.
+
+ acl aclname req_mime_type mime-type1 ...
+ # regex match against the mime type of the request generated
+ # by the client. Can be used to detect file upload or some
+ # types HTTP tunneling requests.
+ # NOTE: This does NOT match the reply. You cannot use this
+ # to match the returned file type.
+
+ acl aclname req_header header-name [-i] any\.regex\.here
+ # regex match against any of the known request headers. May be
+ # thought of as a superset of "browser", "referer" and "mime-type"
+ # ACLs.
+
+ acl aclname rep_mime_type mime-type1 ...
+ # regex match against the mime type of the reply received by
+ # squid. Can be used to detect file download or some
+ # types HTTP tunneling requests.
+ # NOTE: This has no effect in http_access rules. It only has
+ # effect in rules that affect the reply data stream such as
+ # http_reply_access.
+
+ acl aclname rep_header header-name [-i] any\.regex\.here
+ # regex match against any of the known response headers.
+ # Example:
+ #
+ # acl many_spaces rep_header Content-Disposition -i [[:space:]]{3,}
+
+ acl acl_name external class_name [arguments...]
+ # external ACL lookup via a helper class defined by the
+ # external_acl_type directive.
+
+ acl urlgroup group1 ...
+ # match against the urlgroup as indicated by redirectors
+
+ acl aclname user_cert attribute values...
+ # match against attributes in a user SSL certificate
+ # attribute is one of DN/C/O/CN/L/ST
+
+ acl aclname ca_cert attribute values...
+ # match against attributes a users issuing CA SSL certificate
+ # attribute is one of DN/C/O/CN/L/ST
+
+ acl aclname ext_user username ...
+ acl aclname ext_user_regex [-i] pattern ...
+ # string match on username returned by external acl
+ # use REQUIRED to accept any user name.
+Examples:
+acl macaddress arp 09:00:2b:23:45:67
+acl myexample dst_as 1241
+acl password proxy_auth REQUIRED
+acl fileupload req_mime_type -i ^multipart/form-data$
+acl javascript rep_mime_type -i ^application/x-javascript$
+
+NOCOMMENT_START
+#Recommended minimum configuration:
+acl all src 0.0.0.0/0.0.0.0
+acl manager proto cache_object
+acl localhost src 127.0.0.1/255.255.255.255
+acl to_localhost dst 127.0.0.0/8
+acl SSL_ports port 443
+acl Safe_ports port 80 # http
+acl Safe_ports port 21 # ftp
+acl Safe_ports port 443 # https
+acl Safe_ports port 70 # gopher
+acl Safe_ports port 210 # wais
+acl Safe_ports port 1025-65535 # unregistered ports
+acl Safe_ports port 280 # http-mgmt
+acl Safe_ports port 488 # gss-http
+acl Safe_ports port 591 # filemaker
+acl Safe_ports port 777 # multiling http
+acl CONNECT method CONNECT
+NOCOMMENT_END
+DOC_END
+
+NAME: follow_x_forwarded_for
+TYPE: acl_access
+IFDEF: FOLLOW_X_FORWARDED_FOR
+LOC: Config.accessList.followXFF
+DEFAULT: none
+DEFAULT_IF_NONE: deny all
+DOC_START
+ Allowing or Denying the X-Forwarded-For header to be followed to
+ find the original source of a request.
+
+ Requests may pass through a chain of several other proxies
+ before reaching us. The X-Forwarded-For header will contain a
+ comma-separated list of the IP addresses in the chain, with the
+ rightmost address being the most recent.
+
+ If a request reaches us from a source that is allowed by this
+ configuration item, then we consult the X-Forwarded-For header
+ to see where that host received the request from. If the
+ X-Forwarded-For header contains multiple addresses, and if
+ acl_uses_indirect_client is on, then we continue backtracking
+ until we reach an address for which we are not allowed to
+ follow the X-Forwarded-For header, or until we reach the first
+ address in the list. (If acl_uses_indirect_client is off, then
+ it's impossible to backtrack through more than one level of
+ X-Forwarded-For addresses.)
+
+ The end result of this process is an IP address that we will
+ refer to as the indirect client address. This address may
+ be treated as the client address for access control, delay
+ pools and logging, depending on the acl_uses_indirect_client,
+ delay_pool_uses_indirect_client and log_uses_indirect_client
+ options.
+
+ SECURITY CONSIDERATIONS:
+
+ Any host for which we follow the X-Forwarded-For header
+ can place incorrect information in the header, and Squid
+ will use the incorrect information as if it were the
+ source address of the request. This may enable remote
+ hosts to bypass any access control restrictions that are
+ based on the client's source addresses.
+
+ For example:
+
+ acl localhost src 127.0.0.1
+ acl my_other_proxy srcdomain .proxy.example.com
+ follow_x_forwarded_for allow localhost
+ follow_x_forwarded_for allow my_other_proxy
+DOC_END
+
+NAME: acl_uses_indirect_client
+COMMENT: on|off
+TYPE: onoff
+IFDEF: FOLLOW_X_FORWARDED_FOR
+DEFAULT: on
+LOC: Config.onoff.acl_uses_indirect_client
+DOC_START
+ Controls whether the indirect client address
+ (see follow_x_forwarded_for) is used instead of the
+ direct client address in acl matching.
+DOC_END
+
+NAME: delay_pool_uses_indirect_client
+COMMENT: on|off
+TYPE: onoff
+IFDEF: FOLLOW_X_FORWARDED_FOR && DELAY_POOLS
+DEFAULT: on
+LOC: Config.onoff.delay_pool_uses_indirect_client
+DOC_START
+ Controls whether the indirect client address
+ (see follow_x_forwarded_for) is used instead of the
+ direct client address in delay pools.
+DOC_END
+
+NAME: log_uses_indirect_client
+COMMENT: on|off
+TYPE: onoff
+IFDEF: FOLLOW_X_FORWARDED_FOR
+DEFAULT: on
+LOC: Config.onoff.log_uses_indirect_client
+DOC_START
+ Controls whether the indirect client address
+ (see follow_x_forwarded_for) is used instead of the
+ direct client address in the access log.
+DOC_END
+
+NAME: http_access
+TYPE: acl_access
+LOC: Config.accessList.http
+DEFAULT: none
+DEFAULT_IF_NONE: deny all
+DOC_START
+ Allowing or Denying access based on defined access lists
+
+ Access to the HTTP port:
+ http_access allow|deny [!]aclname ...
+
+ NOTE on default values:
+
+ If there are no "access" lines present, the default is to deny
+ the request.
+
+ If none of the "access" lines cause a match, the default is the
+ opposite of the last line in the list. If the last line was
+ deny, the default is allow. Conversely, if the last line
+ is allow, the default will be deny. For these reasons, it is a
+ good idea to have an "deny all" or "allow all" entry at the end
+ of your access lists to avoid potential confusion.
+
+NOCOMMENT_START
+#Recommended minimum configuration:
+#
+# Only allow cachemgr access from localhost
+http_access allow manager localhost
+http_access deny manager
+# Deny requests to unknown ports
+http_access deny !Safe_ports
+# Deny CONNECT to other than SSL ports
+http_access deny CONNECT !SSL_ports
+#
+# We strongly recommend the following be uncommented to protect innocent
+# web applications running on the proxy server who think the only
+# one who can access services on "localhost" is a local user
+#http_access deny to_localhost
+#
+# INSERT YOUR OWN RULE(S) HERE TO ALLOW ACCESS FROM YOUR CLIENTS
+
+# Example rule allowing access from your local networks. Adapt
+# to list your (internal) IP networks from where browsing should
+# be allowed
+#acl our_networks src 192.168.1.0/24 192.168.2.0/24
+#http_access allow our_networks
+
+# And finally deny all other access to this proxy
+http_access deny all
+NOCOMMENT_END
+DOC_END
+
+NAME: http_access2
+TYPE: acl_access
+LOC: Config.accessList.http2
+DEFAULT: none
+DOC_START
+ Allowing or Denying access based on defined access lists
+
+ Identical to http_access, but runs after redirectors. If not set
+ then only http_access is used.
+DOC_END
+
+NAME: http_reply_access
+TYPE: acl_access
+LOC: Config.accessList.reply
+DEFAULT: none
+DEFAULT_IF_NONE: allow all
+DOC_START
+ Allow replies to client requests. This is complementary to http_access.
+
+ http_reply_access allow|deny [!] aclname ...
+
+ NOTE: if there are no access lines present, the default is to allow
+ all replies
+
+ If none of the access lines cause a match the opposite of the
+ last line will apply. Thus it is good practice to end the rules
+ with an "allow all" or "deny all" entry.
+
+NOCOMMENT_START
+#Recommended minimum configuration:
+#
+# Insert your own rules here.
+#
+#
+# and finally allow by default
+http_reply_access allow all
+NOCOMMENT_END
+DOC_END
+
+
+NAME: icp_access
+TYPE: acl_access
+LOC: Config.accessList.icp
+DEFAULT: none
+DEFAULT_IF_NONE: deny all
+DOC_START
+ Allowing or Denying access to the ICP port based on defined
+ access lists
+
+ icp_access allow|deny [!]aclname ...
+
+ See http_access for details
+
+NOCOMMENT_START
+#Allow ICP queries from everyone
+icp_access allow all
+NOCOMMENT_END
+DOC_END
+
+NAME: htcp_access
+IFDEF: USE_HTCP
+TYPE: acl_access
+LOC: Config.accessList.htcp
+DEFAULT: none
+DEFAULT_IF_NONE: deny all
+DOC_START
+ Allowing or Denying access to the HTCP port based on defined
+ access lists
+
+ htcp_access allow|deny [!]aclname ...
+
+ See http_access for details
+
+#Allow HTCP queries from everyone
+htcp_access allow all
+DOC_END
+
+NAME: htcp_clr_access
+IFDEF: USE_HTCP
+TYPE: acl_access
+LOC: Config.accessList.htcp_clr
+DEFAULT: none
+DEFAULT_IF_NONE: deny all
+DOC_START
+ Allowing or Denying access to purge content using HTCP based
+ on defined access lists
+
+ htcp_clr_access allow|deny [!]aclname ...
+
+ See http_access for details
+
+#Allow HTCP CLR requests from trusted peers
+acl htcp_clr_peer src 172.16.1.2
+htcp_clr_access allow htcp_clr_peer
+DOC_END
+
+
+NAME: miss_access
+TYPE: acl_access
+LOC: Config.accessList.miss
+DEFAULT: none
+DOC_START
+ Use to force your neighbors to use you as a sibling instead of
+ a parent. For example:
+
+ acl localclients src 172.16.0.0/16
+ miss_access allow localclients
+ miss_access deny !localclients
+
+ This means only your local clients are allowed to fetch
+ MISSES and all other clients can only fetch HITS.
+
+ By default, allow all clients who passed the http_access rules
+ to fetch MISSES from us.
+
+NOCOMMENT_START
+#Default setting:
+# miss_access allow all
+NOCOMMENT_END
+DOC_END
+
+
+NAME: cache_peer_access
+TYPE: peer_access
+DEFAULT: none
+LOC: none
+DOC_START
+ Similar to 'cache_peer_domain' but provides more flexibility by
+ using ACL elements.
+
+ cache_peer_access cache-host allow|deny [!]aclname ...
+
+ The syntax is identical to 'http_access' and the other lists of
+ ACL elements. See the comments for 'http_access' below, or
+ the Squid FAQ (http://www.squid-cache.org/FAQ/FAQ-10.html).
+DOC_END
+
+NAME: ident_lookup_access
+TYPE: acl_access
+IFDEF: USE_IDENT
+DEFAULT: none
+DEFAULT_IF_NONE: deny all
+LOC: Config.accessList.identLookup
+DOC_START
+ A list of ACL elements which, if matched, cause an ident
+ (RFC931) lookup to be performed for this request. For
+ example, you might choose to always perform ident lookups
+ for your main multi-user Unix boxes, but not for your Macs
+ and PCs. By default, ident lookups are not performed for
+ any requests.
+
+ To enable ident lookups for specific client addresses, you
+ can follow this example:
+
+ acl ident_aware_hosts src 198.168.1.0/255.255.255.0
+ ident_lookup_access allow ident_aware_hosts
+ ident_lookup_access deny all
+
+ Only src type ACL checks are fully supported. A src_domain
+ ACL might work at times, but it will not always provide
+ the correct result.
+DOC_END
+
+NAME: tcp_outgoing_tos tcp_outgoing_ds tcp_outgoing_dscp
+TYPE: acl_tos
+DEFAULT: none
+LOC: Config.accessList.outgoing_tos
+DOC_START
+ Allows you to select a TOS/Diffserv value to mark outgoing
+ connections with, based on the username or source address
+ making the request.
+
+ tcp_outgoing_tos ds-field [!]aclname ...
+
+ Example where normal_service_net uses the TOS value 0x00
+ and normal_service_net uses 0x20
+
+ acl normal_service_net src 10.0.0.0/255.255.255.0
+ acl good_service_net src 10.0.1.0/255.255.255.0
+ tcp_outgoing_tos 0x00 normal_service_net 0x00
+ tcp_outgoing_tos 0x20 good_service_net
+
+ TOS/DSCP values really only have local significance - so you should
+ know what you're specifying. For more information, see RFC2474 and
+ RFC3260.
+
+ The TOS/DSCP byte must be exactly that - a octet value 0 - 255, or
+ "default" to use whatever default your host has. Note that in
+ practice often only values 0 - 63 is usable as the two highest bits
+ have been redefined for use by ECN (RFC3168).
+
+ Processing proceeds in the order specified, and stops at first fully
+ matching line.
+
+ Note: The use of this directive using client dependent ACLs is
+ incompatible with the use of server side persistent connections. To
+ ensure correct results it is best to set server_persisten_connections
+ to off when using this directive in such configurations.
+DOC_END
+
+NAME: tcp_outgoing_address
+TYPE: acl_address
+DEFAULT: none
+LOC: Config.accessList.outgoing_address
+DOC_START
+ Allows you to map requests to different outgoing IP addresses
+ based on the username or source address of the user making
+ the request.
+
+ tcp_outgoing_address ipaddr [[!]aclname] ...
+
+ Example where requests from 10.0.0.0/24 will be forwarded
+ with source address 10.1.0.1, 10.0.2.0/24 forwarded with
+ source address 10.1.0.2 and the rest will be forwarded with
+ source address 10.1.0.3.
+
+ acl normal_service_net src 10.0.0.0/255.255.255.0
+ acl good_service_net src 10.0.1.0/255.255.255.0
+ tcp_outgoing_address 10.0.0.1 normal_service_net
+ tcp_outgoing_address 10.0.0.2 good_service_net
+ tcp_outgoing_address 10.0.0.3
+
+ Processing proceeds in the order specified, and stops at first fully
+ matching line.
+
+ Note: The use of this directive using client dependent ACLs is
+ incompatible with the use of server side persistent connections. To
+ 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
+DEFAULT: 20 KB
+LOC: Config.maxReplyHeaderSize
+DOC_START
+ This specifies the maximum size for HTTP headers in a reply.
+ Reply headers are usually relatively small (about 512 bytes).
+ Placing a limit on the reply header size will catch certain
+ bugs (for example with persistent connections) and possibly
+ buffer-overflow or denial-of-service attacks.
+DOC_END
+
+NAME: reply_body_max_size
+COMMENT: bytes allow|deny acl acl...
+TYPE: body_size_t
+DEFAULT: none
+DEFAULT_IF_NONE: 0 allow all
+LOC: Config.ReplyBodySize
+DOC_START
+ This option specifies the maximum size of a reply body in bytes.
+ It can be used to prevent users from downloading very large files,
+ such as MP3's and movies. When the reply headers are received,
+ the reply_body_max_size lines are processed, and the first line with
+ a result of "allow" is used as the maximum body size for this reply.
+ This size is checked twice. First when we get the reply headers,
+ we check the content-length value. If the content length value exists
+ and is larger than the allowed size, the request is denied and the
+ user receives an error message that says "the request or reply
+ is too large." If there is no content-length, and the reply
+ size exceeds this limit, the client's connection is just closed
+ and they will receive a partial reply.
+
+ WARNING: downstream caches probably can not detect a partial reply
+ if there is no content-length header, so they will cache
+ partial responses and give them out as hits. You should NOT
+ use this option if you have downstream caches.
+
+ If you set this parameter to zero (the default), there will be
+ no limit imposed.
+DOC_END
+
+NAME: log_access
+TYPE: acl_access
+LOC: Config.accessList.log
+DEFAULT: none
+COMMENT: allow|deny acl acl...
+DOC_START
+ This options allows you to control which requests gets logged
+ to access.log (see access_log directive). Requests denied for
+ logging will also not be accounted for in performance counters.
+DOC_END
+
+COMMENT_START
+ ADMINISTRATIVE PARAMETERS
+ -----------------------------------------------------------------------------
+COMMENT_END
+
+NAME: cache_mgr
+TYPE: string
+DEFAULT: webmaster
+LOC: Config.adminEmail
+DOC_START
+ Email-address of local cache manager who will receive
+ mail if the cache dies. The default is "webmaster".
+DOC_END
+
+
+NAME: mail_from
+TYPE: string
+DEFAULT: none
+LOC: Config.EmailFrom
+DOC_START
+ From: email-address for mail sent when the cache dies.
+ The default is to use 'appname@unique_hostname'.
+ Default appname value is "squid", can be changed into
+ src/globals.h before building squid.
+DOC_END
+
+
+NAME: mail_program
+TYPE: eol
+DEFAULT: mail
+LOC: Config.EmailProgram
+DOC_START
+ Email program used to send mail if the cache dies.
+ The default is "mail". The specified program must complain
+ with the standard Unix mail syntax:
+ mail_program recipient < mailfile
+ Optional command line options can be specified.
+DOC_END
+
+
+NAME: cache_effective_user
+TYPE: string
+DEFAULT: nobody
+LOC: Config.effectiveUser
+DOC_START
+ If you start Squid as root, it will change its effective/real
+ UID/GID to the user specified below. The default is to change
+ to UID to nobody. If you define cache_effective_user, but not
+ cache_effective_group, Squid sets the GID to the effective
+ user's default group ID (taken from the password file) and
+ supplementary group list from the from groups membership of
+ cache_effective_user.
+DOC_END
+
+
+NAME: cache_effective_group
+TYPE: string
+DEFAULT: none
+LOC: Config.effectiveGroup
+DOC_START
+ If you want Squid to run with a specific GID regardless of
+ the group memberships of the effective user then set this
+ to the group (or GID) you want Squid to run as. When set
+ all other group privileges of the effective user is ignored
+ and only this GID is effective. If Squid is not started as
+ root the user starting Squid must be member of the specified
+ group.
+DOC_END
+
+
+NAME: httpd_suppress_version_string
+COMMENT: on|off
+TYPE: onoff
+DEFAULT: off
+LOC: Config.onoff.httpd_suppress_version_string
+DOC_START
+ Suppress Squid version string info in HTTP headers and HTML error pages.
+DOC_END
+
+
+NAME: visible_hostname
+TYPE: string
+LOC: Config.visibleHostname
+DEFAULT: none
+DOC_START
+ If you want to present a special hostname in error messages, etc,
+ define this. Otherwise, the return value of gethostname()
+ will be used. If you have multiple caches in a cluster and
+ get errors about IP-forwarding you must set them to have individual
+ names with this setting.
+DOC_END
+
+
+NAME: unique_hostname
+TYPE: string
+LOC: Config.uniqueHostname
+DEFAULT: none
+DOC_START
+ If you want to have multiple machines with the same
+ 'visible_hostname' you must give each machine a different
+ 'unique_hostname' so forwarding loops can be detected.
+DOC_END
+
+
+NAME: hostname_aliases
+TYPE: wordlist
+LOC: Config.hostnameAliases
+DEFAULT: none
+DOC_START
+ A list of other DNS names your cache has.
+DOC_END
+
+NAME: umask
+TYPE: int
+LOC: Config.umask
+DEFAULT: 027
+DOC_START
+ Minimum umask which should be enforced while the proxy
+ is running, in addition to the umask set at startup.
+
+ Note: Should start with a 0 to indicate the normal octal
+ representation of umasks
+DOC_END
+
+COMMENT_START
+ OPTIONS FOR THE CACHE REGISTRATION SERVICE
+ -----------------------------------------------------------------------------
+
+ This section contains parameters for the (optional) cache
+ announcement service. This service is provided to help
+ cache administrators locate one another in order to join or
+ create cache hierarchies.
+
+ An 'announcement' message is sent (via UDP) to the registration
+ service by Squid. By default, the announcement message is NOT
+ SENT unless you enable it with 'announce_period' below.
+
+ The announcement message includes your hostname, plus the
+ following information from this configuration file:
+
+ http_port
+ icp_port
+ cache_mgr
+
+ All current information is processed regularly and made
+ available on the Web at http://www.ircache.net/Cache/Tracker/.
+COMMENT_END
+
+NAME: announce_period
+TYPE: time_t
+LOC: Config.Announce.period
+DEFAULT: 0
+DOC_START
+ This is how frequently to send cache announcements. The
+ default is `0' which disables sending the announcement
+ messages.
+
+ To enable announcing your cache, just uncomment the line
+ below.
+
+NOCOMMENT_START
+#To enable announcing your cache, just uncomment the line below.
+#announce_period 1 day
+NOCOMMENT_END
+DOC_END
+
+
+NAME: announce_host
+TYPE: string
+DEFAULT: tracker.ircache.net
+LOC: Config.Announce.host
+DOC_NONE
+
+NAME: announce_file
+TYPE: string
+DEFAULT: none
+LOC: Config.Announce.file
+DOC_NONE
+
+NAME: announce_port
+TYPE: ushort
+DEFAULT: 3131
+LOC: Config.Announce.port
+DOC_START
+ announce_host and announce_port set the hostname and port
+ number where the registration message will be sent.
+
+ Hostname will default to 'tracker.ircache.net' and port will
+ default default to 3131. If the 'filename' argument is given,
+ the contents of that file will be included in the announce
+ message.
+DOC_END
+
+COMMENT_START
+ HTTPD-ACCELERATOR OPTIONS
+ -----------------------------------------------------------------------------
+COMMENT_END
+
+NAME: httpd_accel_no_pmtu_disc
+COMMENT: on|off
+TYPE: onoff
+DEFAULT: off
+LOC: Config.onoff.accel_no_pmtu_disc
+DOC_START
+ In many setups of transparently intercepting proxies Path-MTU
+ discovery can not work on traffic towards the clients. This is
+ the case when the intercepting device does not fully track
+ connections and fails to forward ICMP must fragment messages
+ to the cache server.
+
+ If you have such setup and experience that certain clients
+ sporadically hang or never complete requests set this to on.
+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
+
+NAME: dns_testnames
+TYPE: wordlist
+LOC: Config.dns_testname_list
+DEFAULT: none
+DEFAULT_IF_NONE: netscape.com internic.net nlanr.net microsoft.com
+DOC_START
+ The DNS tests exit as soon as the first site is successfully looked up
+
+ This test can be disabled with the -D command line option.
+DOC_END
+
+
+NAME: logfile_rotate
+TYPE: int
+DEFAULT: 10
+LOC: Config.Log.rotateNumber
+DOC_START
+ Specifies the number of logfile rotations to make when you
+ type 'squid -k rotate'. The default is 10, which will rotate
+ with extensions 0 through 9. Setting logfile_rotate to 0 will
+ disable the rotation, but the logfiles are still closed and
+ re-opened. This will enable you to rename the logfiles
+ yourself just before sending the rotate signal.
+
+ Note, the 'squid -k rotate' command normally sends a USR1
+ signal to the running squid process. In certain situations
+ (e.g. on Linux with Async I/O), USR1 is used for other
+ purposes, so -k rotate uses another signal. It is best to get
+ in the habit of using 'squid -k rotate' instead of 'kill -USR1
+ '.
+DOC_END
+
+
+NAME: append_domain
+TYPE: string
+LOC: Config.appendDomain
+DEFAULT: none
+DOC_START
+ Appends local domain name to hostnames without any dots in
+ them. append_domain must begin with a period.
+
+ Be warned there are now Internet names with no dots in
+ them using only top-domain names, so setting this may
+ cause some Internet sites to become unavailable.
+
+Example:
+ append_domain .yourdomain.com
+DOC_END
+
+
+NAME: tcp_recv_bufsize
+COMMENT: (bytes)
+TYPE: b_size_t
+DEFAULT: 0 bytes
+LOC: Config.tcpRcvBufsz
+DOC_START
+ Size of receive buffer to set for TCP sockets. Probably just
+ as easy to change your kernel's default. Set to zero to use
+ the default buffer size.
+DOC_END
+
+NAME: error_map
+TYPE: errormap
+LOC: Config.errorMapList
+DEFAULT: none
+DOC_START
+ Map errors to custom messages
+
+ error_map message_url http_status ...
+
+ http_status ... is a list of HTTP status codes or Squid error
+ messages.
+
+ Use in accelerators to substitute the error messages returned
+ by servers with other custom errors.
+
+ error_map http://your.server/error/404.shtml 404
+
+ Requests for error messages is a GET request for the configured
+ URL with the following special headers
+
+ X-Error-Status: The received HTTP status code (i.e. 404)
+ X-Request-URI: The requested URI where the error occurred
+
+ In Addition the following headers are forwarded from the client
+ request:
+
+ User-Agent, Cookie, X-Forwarded-For, Via, Authorization,
+ Accept, Referer
+
+ And the following headers from the server reply:
+
+ Server, Via, Location, Content-Location
+
+ The reply returned to the client will carry the original HTTP
+ headers from the real error message, but with the reply body
+ of the configured error message.
+
+DOC_END
+
+NAME: err_html_text
+TYPE: eol
+LOC: Config.errHtmlText
+DEFAULT: none
+DOC_START
+ HTML text to include in error messages. Make this a "mailto"
+ URL to your admin address, or maybe just a link to your
+ organizations Web page.
+
+ To include this in your error messages, you must rewrite
+ the error template files (found in the "errors" directory).
+ Wherever you want the 'err_html_text' line to appear,
+ insert a %L tag in the error template file.
+DOC_END
+
+NAME: deny_info
+TYPE: denyinfo
+LOC: Config.denyInfoList
+DEFAULT: none
+DOC_START
+ Usage: deny_info err_page_name acl
+ or deny_info http://... acl
+ Example: deny_info ERR_CUSTOM_ACCESS_DENIED bad_guys
+
+ This can be used to return a ERR_ page for requests which
+ do not pass the 'http_access' rules. A single ACL will cause
+ the http_access check to fail. If a 'deny_info' line exists
+ for that ACL Squid returns a corresponding error page.
+
+ You may use ERR_ pages that come with Squid or create your own pages
+ and put them into the configured errors/ directory.
+
+ Alternatively you can specify an error URL. The browsers will
+ get redirected (302) to the specified URL. %s in the redirection
+ URL will be replaced by the requested URL.
+
+ Alternatively you can tell Squid to reset the TCP connection
+ by specifying TCP_RESET.
+DOC_END
+
+NAME: memory_pools
+COMMENT: on|off
+TYPE: onoff
+DEFAULT: on
+LOC: Config.onoff.mem_pools
+DOC_START
+ If set, Squid will keep pools of allocated (but unused) memory
+ available for future use. If memory is a premium on your
+ system and you believe your malloc library outperforms Squid
+ routines, disable this.
+DOC_END
+
+NAME: memory_pools_limit
+COMMENT: (bytes)
+TYPE: b_size_t
+DEFAULT: 5 MB
+LOC: Config.MemPools.limit
+DOC_START
+ Used only with memory_pools on:
+ memory_pools_limit 50 MB
+
+ If set to a non-zero value, Squid will keep at most the specified
+ limit of allocated (but unused) memory in memory pools. All free()
+ requests that exceed this limit will be handled by your malloc
+ library. Squid does not pre-allocate any memory, just safe-keeps
+ objects that otherwise would be free()d. Thus, it is safe to set
+ memory_pools_limit to a reasonably high value even if your
+ configuration will use less memory.
+
+ If set to zero, Squid will keep all memory it can. That is, there
+ will be no limit on the total amount of memory used for safe-keeping.
+
+ To disable memory allocation optimization, do not set
+ memory_pools_limit to 0. Set memory_pools to "off" instead.
+
+ An overhead for maintaining memory pools is not taken into account
+ when the limit is checked. This overhead is close to four bytes per
+ object kept. However, pools may actually _save_ memory because of
+ reduced memory thrashing in your malloc library.
+DOC_END
+
+NAME: via
+IFDEF: HTTP_VIOLATIONS
+COMMENT: on|off
+TYPE: onoff
+DEFAULT: on
+LOC: Config.onoff.via
+DOC_START
+ If set (default), Squid will include a Via header in requests and
+ replies.
+DOC_END
+
+NAME: forwarded_for
+COMMENT: on|off
+TYPE: onoff
+DEFAULT: on
+LOC: opt_forwarded_for
+DOC_START
+ If set, Squid will include your system's IP address or name
+ in the HTTP requests it forwards. By default it looks like
+ this:
+
+ X-Forwarded-For: 192.1.2.3
+
+ If you disable this, it will appear as
+
+ X-Forwarded-For: unknown
+DOC_END
+
+
+NAME: log_icp_queries
+COMMENT: on|off
+TYPE: onoff
+DEFAULT: on
+LOC: Config.onoff.log_udp
+DOC_START
+ If set, ICP queries are logged to access.log. You may wish
+ do disable this if your ICP load is VERY high to speed things
+ up or to simplify log analysis.
+DOC_END
+
+NAME: icp_hit_stale
+COMMENT: on|off
+TYPE: onoff
+DEFAULT: off
+LOC: Config.onoff.icp_hit_stale
+DOC_START
+ If you want to return ICP_HIT for stale cache objects, set this
+ option to 'on'. If you have sibling relationships with caches
+ in other administrative domains, this should be 'off'. If you only
+ have sibling relationships with caches under your control,
+ it is probably okay to set this to 'on'.
+ If set to 'on', your siblings should use the option "allow-miss"
+ on their cache_peer lines for connecting to you.
+DOC_END
+
+
+NAME: minimum_direct_hops
+TYPE: int
+DEFAULT: 4
+LOC: Config.minDirectHops
+DOC_START
+ If using the ICMP pinging stuff, do direct fetches for sites
+ which are no more than this many hops away.
+DOC_END
+
+NAME: minimum_direct_rtt
+TYPE: int
+DEFAULT: 400
+LOC: Config.minDirectRtt
+DOC_START
+ If using the ICMP pinging stuff, do direct fetches for sites
+ which are no more than this many rtt milliseconds away.
+DOC_END
+
+NAME: cachemgr_passwd
+TYPE: cachemgrpasswd
+DEFAULT: none
+LOC: Config.passwd_list
+DOC_START
+ Specify passwords for cachemgr operations.
+
+ Usage: cachemgr_passwd password action action ...
+
+ Some valid actions are (see cache manager menu for a full list):
+ 5min
+ 60min
+ asndb
+ authenticator
+ cbdata
+ client_list
+ comm_incoming
+ config *
+ counters
+ delay
+ digest_stats
+ dns
+ events
+ filedescriptors
+ fqdncache
+ histograms
+ http_headers
+ info
+ io
+ ipcache
+ mem
+ menu
+ netdb
+ non_peers
+ objects
+ offline_toggle *
+ pconn
+ peer_select
+ redirector
+ refresh
+ server_list
+ shutdown *
+ store_digest
+ storedir
+ utilization
+ via_headers
+ vm_objects
+
+ * Indicates actions which will not be performed without a
+ valid password, others can be performed if not listed here.
+
+ To disable an action, set the password to "disable".
+ To allow performing an action without a password, set the
+ password to "none".
+
+ Use the keyword "all" to set the same password for all actions.
+
+Example:
+ cachemgr_passwd secret shutdown
+ cachemgr_passwd lesssssssecret info stats/objects
+ cachemgr_passwd disable all
+DOC_END
+
+NAME: store_avg_object_size
+COMMENT: (kbytes)
+TYPE: kb_size_t
+DEFAULT: 13 KB
+LOC: Config.Store.avgObjectSize
+DOC_START
+ Average object size, used to estimate number of objects your
+ cache can hold. The default is 13 KB.
+DOC_END
+
+NAME: store_objects_per_bucket
+TYPE: int
+DEFAULT: 20
+LOC: Config.Store.objectsPerBucket
+DOC_START
+ Target number of objects per bucket in the store hash table.
+ Lowering this value increases the total number of buckets and
+ also the storage maintenance rate. The default is 50.
+DOC_END
+
+NAME: client_db
+COMMENT: on|off
+TYPE: onoff
+DEFAULT: on
+LOC: Config.onoff.client_db
+DOC_START
+ If you want to disable collecting per-client statistics,
+ turn off client_db here.
+DOC_END
+
+
+NAME: netdb_low
+TYPE: int
+DEFAULT: 900
+LOC: Config.Netdb.low
+DOC_NONE
+
+NAME: netdb_high
+TYPE: int
+DEFAULT: 1000
+LOC: Config.Netdb.high
+DOC_START
+ The low and high water marks for the ICMP measurement
+ database. These are counts, not percents. The defaults are
+ 900 and 1000. When the high water mark is reached, database
+ entries will be deleted until the low mark is reached.
+DOC_END
+
+
+NAME: netdb_ping_period
+TYPE: time_t
+LOC: Config.Netdb.period
+DEFAULT: 5 minutes
+DOC_START
+ The minimum period for measuring a site. There will be at
+ least this much delay between successive pings to the same
+ network. The default is five minutes.
+DOC_END
+
+
+NAME: query_icmp
+COMMENT: on|off
+TYPE: onoff
+DEFAULT: off
+LOC: Config.onoff.query_icmp
+DOC_START
+ If you want to ask your peers to include ICMP data in their ICP
+ replies, enable this option.
+
+ If your peer has configured Squid (during compilation) with
+ '--enable-icmp' that peer will send ICMP pings to origin server
+ sites of the URLs it receives. If you enable this option the
+ ICP replies from that peer will include the ICMP data (if available).
+ Then, when choosing a parent cache, Squid will choose the parent with
+ the minimal RTT to the origin server. When this happens, the
+ hierarchy field of the access.log will be
+ "CLOSEST_PARENT_MISS". This option is off by default.
+DOC_END
+
+NAME: test_reachability
+COMMENT: on|off
+TYPE: onoff
+DEFAULT: off
+LOC: Config.onoff.test_reachability
+DOC_START
+ When this is 'on', ICP MISS replies will be ICP_MISS_NOFETCH
+ instead of ICP_MISS if the target host is NOT in the ICMP
+ database, or has a zero RTT.
+DOC_END
+
+NAME: buffered_logs
+COMMENT: on|off
+TYPE: onoff
+DEFAULT: off
+LOC: Config.onoff.buffered_logs
+DOC_START
+ cache.log log file is written with stdio functions, and as such
+ it can be buffered or unbuffered. By default it will be unbuffered.
+ Buffering it can speed up the writing slightly (though you are
+ unlikely to need to worry unless you run with tons of debugging
+ enabled in which case performance will suffer badly anyway..).
+DOC_END
+
+NAME: reload_into_ims
+IFDEF: HTTP_VIOLATIONS
+COMMENT: on|off
+TYPE: onoff
+DEFAULT: off
+LOC: Config.onoff.reload_into_ims
+DOC_START
+ When you enable this option, client no-cache or ``reload''
+ requests will be changed to If-Modified-Since requests.
+ Doing this VIOLATES the HTTP standard. Enabling this
+ feature could make you liable for problems which it
+ causes.
+
+ see also refresh_pattern for a more selective approach.
+DOC_END
+
+NAME: always_direct
+TYPE: acl_access
+LOC: Config.accessList.AlwaysDirect
+DEFAULT: none
+DOC_START
+ Usage: always_direct allow|deny [!]aclname ...
+
+ Here you can use ACL elements to specify requests which should
+ ALWAYS be forwarded by Squid to the origin servers without using
+ any peers. For example, to always directly forward requests for
+ local servers ignoring any parents or siblings you may have use
+ something like:
+
+ acl local-servers dstdomain my.domain.net
+ always_direct allow local-servers
+
+ To always forward FTP requests directly, use
+
+ acl FTP proto FTP
+ always_direct allow FTP
+
+ NOTE: There is a similar, but opposite option named
+ 'never_direct'. You need to be aware that "always_direct deny
+ foo" is NOT the same thing as "never_direct allow foo". You
+ may need to use a deny rule to exclude a more-specific case of
+ some other rule. Example:
+
+ acl local-external dstdomain external.foo.net
+ acl local-servers dstdomain .foo.net
+ always_direct deny local-external
+ always_direct allow local-servers
+
+ NOTE: If your goal is to make the client forward the request
+ directly to the origin server bypassing Squid then this needs
+ to be done in the client configuration. Squid configuration
+ can only tell Squid how Squid should fetch the object.
+
+ NOTE: This directive is not related to caching. The replies
+ is cached as usual even if you use always_direct. To not cache
+ the replies see no_cache.
+
+ This option replaces some v1.1 options such as local_domain
+ and local_ip.
+DOC_END
+
+NAME: never_direct
+TYPE: acl_access
+LOC: Config.accessList.NeverDirect
+DEFAULT: none
+DOC_START
+ Usage: never_direct allow|deny [!]aclname ...
+
+ never_direct is the opposite of always_direct. Please read
+ the description for always_direct if you have not already.
+
+ With 'never_direct' you can use ACL elements to specify
+ requests which should NEVER be forwarded directly to origin
+ servers. For example, to force the use of a proxy for all
+ requests, except those in your local domain use something like:
+
+ acl local-servers dstdomain .foo.net
+ acl all src 0.0.0.0/0.0.0.0
+ never_direct deny local-servers
+ never_direct allow all
+
+ or if Squid is inside a firewall and there are local intranet
+ servers inside the firewall use something like:
+
+ acl local-intranet dstdomain .foo.net
+ acl local-external dstdomain external.foo.net
+ always_direct deny local-external
+ always_direct allow local-intranet
+ never_direct allow all
+
+ This option replaces some v1.1 options such as inside_firewall
+ and firewall_ip.
+DOC_END
+
+NAME: header_access
+IFDEF: HTTP_VIOLATIONS
+TYPE: http_header_access[]
+LOC: Config.header_access
+DEFAULT: none
+DOC_START
+ Usage: header_access header_name allow|deny [!]aclname ...
+
+ WARNING: Doing this VIOLATES the HTTP standard. Enabling
+ this feature could make you liable for problems which it
+ causes.
+
+ This option replaces the old 'anonymize_headers' and the
+ older 'http_anonymizer' option with something that is much
+ more configurable. This new method creates a list of ACLs
+ for each header, allowing you very fine-tuned header
+ mangling.
+
+ You can only specify known headers for the header name.
+ Other headers are reclassified as 'Other'. You can also
+ refer to all the headers with 'All'.
+
+ For example, to achieve the same behavior as the old
+ 'http_anonymizer standard' option, you should use:
+
+ header_access From deny all
+ header_access Referer deny all
+ header_access Server deny all
+ header_access User-Agent deny all
+ header_access WWW-Authenticate deny all
+ header_access Link deny all
+
+ Or, to reproduce the old 'http_anonymizer paranoid' feature
+ you should use:
+
+ header_access Allow allow all
+ header_access Authorization allow all
+ header_access WWW-Authenticate allow all
+ header_access Proxy-Authorization allow all
+ header_access Proxy-Authenticate allow all
+ header_access Cache-Control allow all
+ header_access Content-Encoding allow all
+ header_access Content-Length allow all
+ header_access Content-Type allow all
+ header_access Date allow all
+ header_access Expires allow all
+ header_access Host allow all
+ header_access If-Modified-Since allow all
+ header_access Last-Modified allow all
+ header_access Location allow all
+ header_access Pragma allow all
+ header_access Accept allow all
+ header_access Accept-Charset allow all
+ header_access Accept-Encoding allow all
+ header_access Accept-Language allow all
+ header_access Content-Language allow all
+ header_access Mime-Version allow all
+ header_access Retry-After allow all
+ header_access Title allow all
+ header_access Connection allow all
+ header_access Proxy-Connection allow all
+ header_access All deny all
+
+ By default, all headers are allowed (no anonymizing is
+ performed).
+DOC_END
+
+NAME: header_replace
+IFDEF: HTTP_VIOLATIONS
+TYPE: http_header_replace[]
+LOC: Config.header_access
+DEFAULT: none
+DOC_START
+ Usage: header_replace header_name message
+ Example: header_replace User-Agent Nutscrape/1.0 (CP/M; 8-bit)
+
+ This option allows you to change the contents of headers
+ denied with header_access above, by replacing them with
+ some fixed string. This replaces the old fake_user_agent
+ option.
+
+ By default, headers are removed if denied.
+DOC_END
+
+NAME: icon_directory
+TYPE: string
+LOC: Config.icons.directory
+DEFAULT: @DEFAULT_ICON_DIR@
+DOC_START
+ Where the icons are stored. These are normally kept in
+ @DEFAULT_ICON_DIR@
+DOC_END
+
+NAME: global_internal_static
+TYPE: onoff
+LOC: Config.onoff.global_internal_static
+DEFAULT: on
+DOC_START
+ This directive controls is Squid should intercept all requests for
+ /squid-internal-static/ no matter which host the URL is requesting
+ (default on setting), or if nothing special should be done for
+ such URLs (off setting). The purpose of this directive is to make
+ icons etc work better in complex cache hierarchies where it may
+ not always be possible for all corners in the cache mesh to reach
+ the server generating a directory listing.
+DOC_END
+
+NAME: short_icon_urls
+TYPE: onoff
+LOC: Config.icons.use_short_names
+DEFAULT: off
+DOC_START
+ If this is enabled Squid will use short URLs for icons.
+
+ If off the URLs for icons will always be absolute URLs
+ including the proxy name and port.
+DOC_END
+
+NAME: error_directory
+TYPE: string
+LOC: Config.errorDirectory
+DEFAULT: @DEFAULT_ERROR_DIR@
+DOC_START
+ If you wish to create your own versions of the default
+ (English) error files, either to customize them to suit your
+ language or company copy the template English files to another
+ directory and point this tag at them.
+DOC_END
+
+NAME: maximum_single_addr_tries
+TYPE: int
+LOC: Config.retry.maxtries
+DEFAULT: 1
+DOC_START
+ This sets the maximum number of connection attempts for a
+ host that only has one address (for multiple-address hosts,
+ each address is tried once).
+
+ The default value is one attempt, the (not recommended)
+ maximum is 255 tries. A warning message will be generated
+ if it is set to a value greater than ten.
+
+ Note: This is in addition to the request re-forwarding which
+ takes place if Squid fails to get a satisfying response.
+DOC_END
+
+NAME: retry_on_error
+TYPE: onoff
+LOC: Config.retry.onerror
+DEFAULT: off
+DOC_START
+ If set to on Squid will automatically retry requests when
+ receiving an error response. This is mainly useful if you
+ are in a complex cache hierarchy to work around access
+ control errors.
+DOC_END
+
+NAME: snmp_port
+TYPE: ushort
+LOC: Config.Port.snmp
+DEFAULT: 3401
+IFDEF: SQUID_SNMP
+DOC_START
+ Squid can now serve statistics and status information via SNMP.
+ By default it listens to port 3401 on the machine. If you don't
+ wish to use SNMP, set this to "0".
+DOC_END
+
+NAME: snmp_access
+TYPE: acl_access
+LOC: Config.accessList.snmp
+DEFAULT: none
+DEFAULT_IF_NONE: deny all
+IFDEF: SQUID_SNMP
+DOC_START
+ Allowing or denying access to the SNMP port.
+
+ All access to the agent is denied by default.
+ usage:
+
+ snmp_access allow|deny [!]aclname ...
+
+Example:
+ snmp_access allow snmppublic localhost
+ snmp_access deny all
+DOC_END
+
+NAME: snmp_incoming_address
+TYPE: address
+LOC: Config.Addrs.snmp_incoming
+DEFAULT: 0.0.0.0
+IFDEF: SQUID_SNMP
+DOC_NONE
+NAME: snmp_outgoing_address
+TYPE: address
+LOC: Config.Addrs.snmp_outgoing
+DEFAULT: 255.255.255.255
+IFDEF: SQUID_SNMP
+DOC_START
+ Just like 'udp_incoming_address' above, but for the SNMP port.
+
+ snmp_incoming_address is used for the SNMP socket receiving
+ messages from SNMP agents.
+ snmp_outgoing_address is used for SNMP packets returned to SNMP
+ agents.
+
+ The default snmp_incoming_address (0.0.0.0) is to listen on all
+ available network interfaces.
+
+ If snmp_outgoing_address is set to 255.255.255.255 (the default)
+ it will use the same socket as snmp_incoming_address. Only
+ change this if you want to have SNMP replies sent using another
+ address than where this Squid listens for SNMP queries.
+
+ NOTE, snmp_incoming_address and snmp_outgoing_address can not have
+ the same value since they both use port 3401.
+DOC_END
+
+NAME: as_whois_server
+TYPE: string
+LOC: Config.as_whois_server
+DEFAULT: whois.ra.net
+DEFAULT_IF_NONE: whois.ra.net
+DOC_START
+ WHOIS server to query for AS numbers. NOTE: AS numbers are
+ queried only when Squid starts up, not for every request.
+DOC_END
+
+NAME: wccp_router
+TYPE: address
+LOC: Config.Wccp.router
+DEFAULT: 0.0.0.0
+IFDEF: USE_WCCP
+DOC_NONE
+NAME: wccp2_router
+TYPE: sockaddr_in_list
+LOC: Config.Wccp2.router
+DEFAULT: none
+IFDEF: USE_WCCPv2
+DOC_START
+ Use this option to define your WCCP ``home'' router for
+ Squid.
+
+ wccp_router supports a single WCCP(v1) router
+
+ wccp2_router supports multiple WCCPv2 routers
+
+ only one of the two may be used at the same time and defines
+ which version of WCCP to use.
+DOC_END
+
+NAME: wccp_version
+TYPE: int
+LOC: Config.Wccp.version
+DEFAULT: 4
+IFDEF: USE_WCCP
+DOC_START
+ This directive is only relevant if you need to set up WCCP(v1)
+ to some very old and end-of-life Cisco routers. In all other
+ setups it must be left unset or at the default setting.
+ It defines an internal version in the WCCP(v1) protocol,
+ with version 4 being the officially documented protocol.
+
+ According to some users, Cisco IOS 11.2 and earlier only
+ support WCCP version 3. If you're using that or an earlier
+ version of IOS, you may need to change this value to 3, otherwise
+ do not specify this parameter.
+DOC_END
+
+NAME: wccp2_rebuild_wait
+TYPE: onoff
+LOC: Config.Wccp2.rebuildwait
+DEFAULT: on
+IFDEF: USE_WCCPv2
+DOC_START
+ If this is enabled Squid will wait for the cache dir rebuild to finish
+ before sending the first wccp2 HereIAm packet
+DOC_END
+
+NAME: wccp2_forwarding_method
+TYPE: int
+LOC: Config.Wccp2.forwarding_method
+DEFAULT: 1
+IFDEF: USE_WCCPv2
+DOC_START
+ WCCP2 allows the setting of forwarding methods between the
+ router/switch and the cache. Valid values are as follows:
+
+ 1 - GRE encapsulation (forward the packet in a GRE/WCCP tunnel)
+ 2 - L2 redirect (forward the packet using Layer 2/MAC rewriting)
+
+ Currently (as of IOS 12.4) cisco routers only support GRE.
+ Cisco switches only support the L2 redirect assignment method.
+DOC_END
+
+NAME: wccp2_return_method
+TYPE: int
+LOC: Config.Wccp2.return_method
+DEFAULT: 1
+IFDEF: USE_WCCPv2
+DOC_START
+ WCCP2 allows the setting of return methods between the
+ router/switch and the cache for packets that the cache
+ decides not to handle. Valid values are as follows:
+
+ 1 - GRE encapsulation (forward the packet in a GRE/WCCP tunnel)
+ 2 - L2 redirect (forward the packet using Layer 2/MAC rewriting)
+
+ Currently (as of IOS 12.4) cisco routers only support GRE.
+ Cisco switches only support the L2 redirect assignment.
+
+ If the "ip wccp redirect exclude in" command has been
+ enabled on the cache interface, then it is still safe for
+ the proxy server to use a l2 redirect method even if this
+ option is set to GRE.
+DOC_END
+
+NAME: wccp2_assignment_method
+TYPE: int
+LOC: Config.Wccp2.assignment_method
+DEFAULT: 1
+IFDEF: USE_WCCPv2
+DOC_START
+ WCCP2 allows the setting of methods to assign the WCCP hash
+ Valid values are as follows:
+
+ 1 - Hash assignment
+ 2 - Mask assignment
+
+ As a general rule, cisco routers support the hash assignment method
+ and cisco switches support the mask assignment method.
+DOC_END
+
+NAME: wccp2_service
+TYPE: wccp2_service
+LOC: Config.Wccp2.info
+DEFAULT: none
+DEFAULT_IF_NONE: standard 0
+IFDEF: USE_WCCPv2
+DOC_START
+ WCCP2 allows for multiple traffic services. There are two
+ types: "standard" and "dynamic". The standard type defines
+ one service id - http (id 0). The dynamic service ids can be from
+ 51 to 255 inclusive. In order to use a dynamic service id
+ one must define the type of traffic to be redirected; this is done
+ using the wccp2_service_info option.
+
+ The "standard" type does not require a wccp2_service_info option,
+ just specifying the service id will suffice.
+
+ MD5 service authentication can be enabled by adding
+ "password=" to the end of this service declaration.
+
+ Examples:
+
+ wccp2_service standard 0 # for the 'web-cache' standard service
+ wccp2_service dynamic 80 # a dynamic service type which will be
+ # fleshed out with subsequent options.
+ wccp2_service standard 0 password=foo
+
+DOC_END
+
+NAME: wccp2_service_info
+TYPE: wccp2_service_info
+LOC: Config.Wccp2.info
+DEFAULT: none
+IFDEF: USE_WCCPv2
+DOC_START
+ Dynamic WCCPv2 services require further information to define the
+ traffic you wish to have diverted.
+
+ The format is:
+
+ wccp2_service_info protocol= flags=,..
+ priority= ports=,..
+
+ The relevant WCCPv2 flags:
+ + src_ip_hash, dst_ip_hash
+ + source_port_hash, dest_port_hash
+ + src_ip_alt_hash, dst_ip_alt_hash
+ + src_port_alt_hash, dst_port_alt_hash
+ + ports_source
+
+ The port list can be one to eight entries.
+
+ Example:
+
+ wccp2_service_info 80 protocol=tcp flags=src_ip_hash,ports_source
+ priority=240 ports=80
+
+ Note: the service id must have been defined by a previous
+ 'wccp2_service dynamic ' entry.
+DOC_END
+
+NAME: wccp2_weight
+TYPE: int
+LOC: Config.Wccp2.weight
+DEFAULT: 10000
+IFDEF: USE_WCCPv2
+DOC_START
+ Each cache server gets assigned a set of the destination
+ hash proportional to their weight.
+DOC_END
+
+NAME: wccp_address
+TYPE: address
+LOC: Config.Wccp.address
+DEFAULT: 0.0.0.0
+IFDEF: USE_WCCP
+DOC_NONE
+NAME: wccp2_address
+TYPE: address
+LOC: Config.Wccp2.address
+DEFAULT: 0.0.0.0
+IFDEF: USE_WCCPv2
+DOC_START
+ Use this option if you require WCCP to use a specific
+ interface address.
+
+ The default behavior is to not bind to any specific address.
+DOC_END
+
+
+COMMENT_START
+ DELAY POOL PARAMETERS (all require DELAY_POOLS compilation option)
+ -----------------------------------------------------------------------------
+COMMENT_END
+
+NAME: delay_pools
+TYPE: delay_pool_count
+DEFAULT: 0
+IFDEF: DELAY_POOLS
+LOC: Config.Delay
+DOC_START
+ This represents the number of delay pools to be used. For example,
+ if you have one class 2 delay pool and one class 3 delays pool, you
+ have a total of 2 delay pools.
+DOC_END
+
+NAME: delay_class
+TYPE: delay_pool_class
+DEFAULT: none
+IFDEF: DELAY_POOLS
+LOC: Config.Delay
+DOC_START
+ This defines the class of each delay pool. There must be exactly one
+ delay_class line for each delay pool. For example, to define two
+ delay pools, one of class 2 and one of class 3, the settings above
+ and here would be:
+
+Example:
+ delay_pools 2 # 2 delay pools
+ delay_class 1 2 # pool 1 is a class 2 pool
+ delay_class 2 3 # pool 2 is a class 3 pool
+
+ The delay pool classes are:
+
+ class 1 Everything is limited by a single aggregate
+ bucket.
+
+ class 2 Everything is limited by a single aggregate
+ bucket as well as an "individual" bucket chosen
+ from bits 25 through 32 of the IP address.
+
+ class 3 Everything is limited by a single aggregate
+ bucket as well as a "network" bucket chosen
+ from bits 17 through 24 of the IP address and a
+ "individual" bucket chosen from bits 17 through
+ 32 of the IP address.
+
+ NOTE: If an IP address is a.b.c.d
+ -> bits 25 through 32 are "d"
+ -> bits 17 through 24 are "c"
+ -> bits 17 through 32 are "c * 256 + d"
+DOC_END
+
+NAME: delay_access
+TYPE: delay_pool_access
+DEFAULT: none
+IFDEF: DELAY_POOLS
+LOC: Config.Delay
+DOC_START
+ This is used to determine which delay pool a request falls into.
+
+ delay_access is sorted per pool and the matching starts with pool 1,
+ then pool 2, ..., and finally pool N. The first delay pool where the
+ request is allowed is selected for the request. If it does not allow
+ the request to any pool then the request is not delayed (default).
+
+ For example, if you want some_big_clients in delay
+ pool 1 and lotsa_little_clients in delay pool 2:
+
+Example:
+ delay_access 1 allow some_big_clients
+ delay_access 1 deny all
+ delay_access 2 allow lotsa_little_clients
+ delay_access 2 deny all
+DOC_END
+
+NAME: delay_parameters
+TYPE: delay_pool_rates
+DEFAULT: none
+IFDEF: DELAY_POOLS
+LOC: Config.Delay
+DOC_START
+ This defines the parameters for a delay pool. Each delay pool has
+ a number of "buckets" associated with it, as explained in the
+ description of delay_class. For a class 1 delay pool, the syntax is:
+
+delay_parameters pool aggregate
+
+ For a class 2 delay pool:
+
+delay_parameters pool aggregate individual
+
+ For a class 3 delay pool:
+
+delay_parameters pool aggregate network individual
+
+ The variables here are:
+
+ pool a pool number - ie, a number between 1 and the
+ number specified in delay_pools as used in
+ delay_class lines.
+
+ aggregate the "delay parameters" for the aggregate bucket
+ (class 1, 2, 3).
+
+ individual the "delay parameters" for the individual
+ buckets (class 2, 3).
+
+ network the "delay parameters" for the network buckets
+ (class 3).
+
+ A pair of delay parameters is written restore/maximum, where restore is
+ the number of bytes (not bits - modem and network speeds are usually
+ quoted in bits) per second placed into the bucket, and maximum is the
+ maximum number of bytes which can be in the bucket at any time.
+
+ For example, if delay pool number 1 is a class 2 delay pool as in the
+ above example, and is being used to strictly limit each host to 64kbps
+ (plus overheads), with no overall limit, the line is:
+
+delay_parameters 1 -1/-1 8000/8000
+
+ Note that the figure -1 is used to represent "unlimited".
+
+ And, if delay pool number 2 is a class 3 delay pool as in the above
+ example, and you want to limit it to a total of 256kbps (strict limit)
+ with each 8-bit network permitted 64kbps (strict limit) and each
+ individual host permitted 4800bps with a bucket maximum size of 64kb
+ to permit a decent web page to be downloaded at a decent speed
+ (if the network is not being limited due to overuse) but slow down
+ large downloads more significantly:
+
+delay_parameters 2 32000/32000 8000/8000 600/8000
+
+ There must be one delay_parameters line for each delay pool.
+DOC_END
+
+NAME: delay_initial_bucket_level
+COMMENT: (percent, 0-100)
+TYPE: ushort
+DEFAULT: 50
+IFDEF: DELAY_POOLS
+LOC: Config.Delay.initial
+DOC_START
+ The initial bucket percentage is used to determine how much is put
+ in each bucket when squid starts, is reconfigured, or first notices
+ a host accessing it (in class 2 and class 3, individual hosts and
+ networks only have buckets associated with them once they have been
+ "seen" by squid).
+DOC_END
+
+NAME: incoming_icp_average
+TYPE: int
+DEFAULT: 6
+LOC: Config.comm_incoming.icp_average
+DOC_NONE
+
+NAME: incoming_http_average
+TYPE: int
+DEFAULT: 4
+LOC: Config.comm_incoming.http_average
+DOC_NONE
+
+NAME: incoming_dns_average
+TYPE: int
+DEFAULT: 4
+LOC: Config.comm_incoming.dns_average
+DOC_NONE
+
+NAME: min_icp_poll_cnt
+TYPE: int
+DEFAULT: 8
+LOC: Config.comm_incoming.icp_min_poll
+DOC_NONE
+
+NAME: min_dns_poll_cnt
+TYPE: int
+DEFAULT: 8
+LOC: Config.comm_incoming.dns_min_poll
+DOC_NONE
+
+NAME: min_http_poll_cnt
+TYPE: int
+DEFAULT: 8
+LOC: Config.comm_incoming.http_min_poll
+DOC_START
+ Heavy voodoo here. I can't even believe you are reading this.
+ Are you crazy? Don't even think about adjusting these unless
+ you understand the algorithms in comm_select.c first!
+DOC_END
+
+NAME: max_open_disk_fds
+TYPE: int
+LOC: Config.max_open_disk_fds
+DEFAULT: 0
+DOC_START
+ To avoid having disk as the I/O bottleneck Squid can optionally
+ bypass the on-disk cache if more than this amount of disk file
+ descriptors are open.
+
+ A value of 0 indicates no limit.
+DOC_END
+
+NAME: offline_mode
+TYPE: onoff
+LOC: Config.onoff.offline
+DEFAULT: off
+DOC_START
+ Enable this option and Squid will never try to validate cached
+ objects.
+DOC_END
+
+NAME: uri_whitespace
+TYPE: uri_whitespace
+LOC: Config.uri_whitespace
+DEFAULT: strip
+DOC_START
+ What to do with requests that have whitespace characters in the
+ URI. Options:
+
+ strip: The whitespace characters are stripped out of the URL.
+ This is the behavior recommended by RFC2396.
+ deny: The request is denied. The user receives an "Invalid
+ Request" message.
+ allow: The request is allowed and the URI is not changed. The
+ whitespace characters remain in the URI. Note the
+ whitespace is passed to redirector processes if they
+ are in use.
+ encode: The request is allowed and the whitespace characters are
+ encoded according to RFC1738. This could be considered
+ a violation of the HTTP/1.1
+ RFC because proxies are not allowed to rewrite URI's.
+ chop: The request is allowed and the URI is chopped at the
+ first whitespace. This might also be considered a
+ violation.
+DOC_END
+
+NAME: broken_posts
+TYPE: acl_access
+DEFAULT: none
+LOC: Config.accessList.brokenPosts
+DOC_START
+ A list of ACL elements which, if matched, causes Squid to send
+ an extra CRLF pair after the body of a PUT/POST request.
+
+ Some HTTP servers has broken implementations of PUT/POST,
+ and rely on an extra CRLF pair sent by some WWW clients.
+
+ Quote from RFC2068 section 4.1 on this matter:
+
+ Note: certain buggy HTTP/1.0 client implementations generate an
+ extra CRLF's after a POST request. To restate what is explicitly
+ forbidden by the BNF, an HTTP/1.1 client must not preface or follow
+ a request with an extra CRLF.
+
+Example:
+ acl buggy_server url_regex ^http://....
+ broken_posts allow buggy_server
+DOC_END
+
+NAME: mcast_miss_addr
+IFDEF: MULTICAST_MISS_STREAM
+TYPE: address
+LOC: Config.mcast_miss.addr
+DEFAULT: 255.255.255.255
+DOC_START
+ If you enable this option, every "cache miss" URL will
+ be sent out on the specified multicast address.
+
+ Do not enable this option unless you are are absolutely
+ certain you understand what you are doing.
+DOC_END
+
+NAME: mcast_miss_ttl
+IFDEF: MULTICAST_MISS_STREAM
+TYPE: ushort
+LOC: Config.mcast_miss.ttl
+DEFAULT: 16
+DOC_START
+ This is the time-to-live value for packets multicasted
+ when multicasting off cache miss URLs is enabled. By
+ default this is set to 'site scope', i.e. 16.
+DOC_END
+
+NAME: mcast_miss_port
+IFDEF: MULTICAST_MISS_STREAM
+TYPE: ushort
+LOC: Config.mcast_miss.port
+DEFAULT: 3135
+DOC_START
+ This is the port number to be used in conjunction with
+ 'mcast_miss_addr'.
+DOC_END
+
+NAME: mcast_miss_encode_key
+IFDEF: MULTICAST_MISS_STREAM
+TYPE: string
+LOC: Config.mcast_miss.encode_key
+DEFAULT: XXXXXXXXXXXXXXXX
+DOC_START
+ The URLs that are sent in the multicast miss stream are
+ encrypted. This is the encryption key.
+DOC_END
+
+NAME: nonhierarchical_direct
+TYPE: onoff
+LOC: Config.onoff.nonhierarchical_direct
+DEFAULT: on
+DOC_START
+ By default, Squid will send any non-hierarchical requests
+ (matching hierarchy_stoplist or not cacheable request type) direct
+ to origin servers.
+
+ If you set this to off, Squid will prefer to send these
+ requests to parents.
+
+ Note that in most configurations, by turning this off you will only
+ add latency to these request without any improvement in global hit
+ ratio.
+
+ If you are inside an firewall see never_direct instead of
+ this directive.
+DOC_END
+
+NAME: prefer_direct
+TYPE: onoff
+LOC: Config.onoff.prefer_direct
+DEFAULT: off
+DOC_START
+ Normally Squid tries to use parents for most requests. If you for some
+ reason like it to first try going direct and only use a parent if
+ going direct fails set this to on.
+
+ By combining nonhierarchical_direct off and prefer_direct on you
+ can set up Squid to use a parent as a backup path if going direct
+ fails.
+
+ Note: If you want Squid to use parents for all requests see
+ the never_direct directive. prefer_direct only modifies how Squid
+ acts on cacheable requests.
+DOC_END
+
+NAME: strip_query_terms
+TYPE: onoff
+LOC: Config.onoff.strip_query_terms
+DEFAULT: on
+DOC_START
+ By default, Squid strips query terms from requested URLs before
+ logging. This protects your user's privacy.
+DOC_END
+
+NAME: coredump_dir
+TYPE: string
+LOC: Config.coredump_dir
+DEFAULT: none
+DEFAULT_IF_NONE: none
+DOC_START
+ By default Squid leaves core files in the directory from where
+ it was started. If you set 'coredump_dir' to a directory
+ that exists, Squid will chdir() to that directory at startup
+ and coredump files will be left there.
+
+NOCOMMENT_START
+# Leave coredumps in the first cache dir
+coredump_dir @DEFAULT_SWAP_DIR@
+NOCOMMENT_END
+DOC_END
+
+NAME: redirector_bypass
+TYPE: onoff
+LOC: Config.onoff.redirector_bypass
+DEFAULT: off
+DOC_START
+ When this is 'on', a request will not go through the
+ redirector if all redirectors are busy. If this is 'off'
+ and the redirector queue grows too large, Squid will exit
+ with a FATAL error and ask you to increase the number of
+ redirectors. You should only enable this if the redirectors
+ are not critical to your caching system. If you use
+ redirectors for access control, and you enable this option,
+ users may have access to pages they should not
+ be allowed to request.
+DOC_END
+
+NAME: ignore_unknown_nameservers
+TYPE: onoff
+LOC: Config.onoff.ignore_unknown_nameservers
+DEFAULT: on
+DOC_START
+ By default Squid checks that DNS responses are received
+ from the same IP addresses they are sent to. If they
+ don't match, Squid ignores the response and writes a warning
+ message to cache.log. You can allow responses from unknown
+ nameservers by setting this option to 'off'.
+DOC_END
+
+NAME: digest_generation
+IFDEF: USE_CACHE_DIGESTS
+TYPE: onoff
+LOC: Config.onoff.digest_generation
+DEFAULT: on
+DOC_START
+ This controls whether the server will generate a Cache Digest
+ of its contents. By default, Cache Digest generation is
+ enabled if Squid is compiled with USE_CACHE_DIGESTS defined.
+DOC_END
+
+NAME: digest_bits_per_entry
+IFDEF: USE_CACHE_DIGESTS
+TYPE: int
+LOC: Config.digest.bits_per_entry
+DEFAULT: 5
+DOC_START
+ This is the number of bits of the server's Cache Digest which
+ will be associated with the Digest entry for a given HTTP
+ Method and URL (public key) combination. The default is 5.
+DOC_END
+
+NAME: digest_rebuild_period
+IFDEF: USE_CACHE_DIGESTS
+COMMENT: (seconds)
+TYPE: time_t
+LOC: Config.digest.rebuild_period
+DEFAULT: 1 hour
+DOC_START
+ This is the number of seconds between Cache Digest rebuilds.
+DOC_END
+
+NAME: digest_rewrite_period
+COMMENT: (seconds)
+IFDEF: USE_CACHE_DIGESTS
+TYPE: time_t
+LOC: Config.digest.rewrite_period
+DEFAULT: 1 hour
+DOC_START
+ This is the number of seconds between Cache Digest writes to
+ disk.
+DOC_END
+
+NAME: digest_swapout_chunk_size
+COMMENT: (bytes)
+TYPE: b_size_t
+IFDEF: USE_CACHE_DIGESTS
+LOC: Config.digest.swapout_chunk_size
+DEFAULT: 4096 bytes
+DOC_START
+ This is the number of bytes of the Cache Digest to write to
+ disk at a time. It defaults to 4096 bytes (4KB), the Squid
+ default swap page.
+DOC_END
+
+NAME: digest_rebuild_chunk_percentage
+COMMENT: (percent, 0-100)
+IFDEF: USE_CACHE_DIGESTS
+TYPE: int
+LOC: Config.digest.rebuild_chunk_percentage
+DEFAULT: 10
+DOC_START
+ This is the percentage of the Cache Digest to be scanned at a
+ time. By default it is set to 10% of the Cache Digest.
+DOC_END
+
+NAME: chroot
+TYPE: string
+LOC: Config.chroot_dir
+DEFAULT: none
+DOC_START
+ Use this to have Squid do a chroot() while initializing. This
+ also causes Squid to fully drop root privileges after
+ initializing. This means, for example, that if you use a HTTP
+ port less than 1024 and try to reconfigure, you will get an
+ error.
+DOC_END
+
+NAME: client_persistent_connections
+TYPE: onoff
+LOC: Config.onoff.client_pconns
+DEFAULT: on
+DOC_NONE
+
+NAME: server_persistent_connections
+TYPE: onoff
+LOC: Config.onoff.server_pconns
+DEFAULT: on
+DOC_START
+ Persistent connection support for clients and servers. By
+ default, Squid uses persistent connections (when allowed)
+ with its clients and servers. You can use these options to
+ disable persistent connections with clients and/or servers.
+DOC_END
+
+NAME: persistent_connection_after_error
+TYPE: onoff
+LOC: Config.onoff.error_pconns
+DEFAULT: off
+DOC_START
+ With this directive the use of persistent connections after
+ HTTP errors can be disabled. Useful if you have clients
+ who fail to handle errors on persistent connections proper.
+DOC_END
+
+NAME: detect_broken_pconn
+TYPE: onoff
+LOC: Config.onoff.detect_broken_server_pconns
+DEFAULT: off
+DOC_START
+ Some servers have been found to incorrectly signal the use
+ of HTTP/1.0 persistent connections even on replies not
+ compatible, causing significant delays. This server problem
+ has mostly been seen on redirects.
+
+ By enabling this directive Squid attempts to detect such
+ broken replies and automatically assume the reply is finished
+ after 10 seconds timeout.
+DOC_END
+
+NAME: balance_on_multiple_ip
+TYPE: onoff
+LOC: Config.onoff.balance_on_multiple_ip
+DEFAULT: on
+DOC_START
+ Some load balancing servers based on round robin DNS have been
+ found not to preserve user session state across requests
+ to different IP addresses.
+
+ By default Squid rotates IP's per request. By disabling
+ this directive only connection failure triggers rotation.
+DOC_END
+
+NAME: pipeline_prefetch
+TYPE: onoff
+LOC: Config.onoff.pipeline_prefetch
+DEFAULT: off
+DOC_START
+ To boost the performance of pipelined requests to closer
+ match that of a non-proxied environment Squid can try to fetch
+ up to two requests in parallel from a pipeline.
+
+ Defaults to off for bandwidth management and access logging
+ reasons.
+DOC_END
+
+NAME: extension_methods
+TYPE: extension_method
+LOC: RequestMethodStr
+DEFAULT: none
+DOC_START
+ Squid only knows about standardized HTTP request methods.
+ You can add up to 20 additional "extension" methods here.
+DOC_END
+
+NAME: request_entities
+TYPE: onoff
+LOC: Config.onoff.request_entities
+DEFAULT: off
+DOC_START
+ Squid defaults to deny GET and HEAD requests with request entities,
+ as the meaning of such requests are undefined in the HTTP standard
+ even if not explicitly forbidden.
+
+ Set this directive to on if you have clients which insists
+ on sending request entities in GET or HEAD requests. But be warned
+ that there is server software (both proxies and web servers) which
+ can fail to properly process this kind of request which may make you
+ vulnerable to cache pollution attacks if enabled.
+DOC_END
+
+NAME: high_response_time_warning
+TYPE: int
+COMMENT: (msec)
+LOC: Config.warnings.high_rptm
+DEFAULT: 0
+DOC_START
+ If the one-minute median response time exceeds this value,
+ Squid prints a WARNING with debug level 0 to get the
+ administrators attention. The value is in milliseconds.
+DOC_END
+
+NAME: high_page_fault_warning
+TYPE: int
+LOC: Config.warnings.high_pf
+DEFAULT: 0
+DOC_START
+ If the one-minute average page fault rate exceeds this
+ value, Squid prints a WARNING with debug level 0 to get
+ the administrators attention. The value is in page faults
+ per second.
+DOC_END
+
+NAME: high_memory_warning
+TYPE: b_size_t
+LOC: Config.warnings.high_memory
+DEFAULT: 0
+DOC_START
+ If the memory usage (as determined by mallinfo) exceeds
+ value, Squid prints a WARNING with debug level 0 to get
+ the administrators attention.
+DOC_END
+
+NAME: store_dir_select_algorithm
+TYPE: string
+LOC: Config.store_dir_select_algorithm
+DEFAULT: least-load
+DOC_START
+ Set this to 'round-robin' as an alternative.
+DOC_END
+
+NAME: forward_log
+IFDEF: WIP_FWD_LOG
+TYPE: string
+DEFAULT: none
+LOC: Config.Log.forward
+DOC_START
+ Logs the server-side requests.
+
+ This is currently work in progress.
+DOC_END
+
+NAME: ie_refresh
+COMMENT: on|off
+TYPE: onoff
+LOC: Config.onoff.ie_refresh
+DEFAULT: off
+DOC_START
+ Microsoft Internet Explorer up until version 5.5 Service
+ Pack 1 has an issue with transparent proxies, wherein it
+ is impossible to force a refresh. Turning this on provides
+ a partial fix to the problem, by causing all IMS-REFRESH
+ requests from older IE versions to check the origin server
+ for fresh content. This reduces hit ratio by some amount
+ (~10% in my experience), but allows users to actually get
+ fresh content when they want it. Note that because Squid
+ cannot tell if the user is using 5.5 or 5.5SP1, the behavior
+ of 5.5 is unchanged from old versions of Squid (i.e. a
+ forced refresh is impossible). Newer versions of IE will,
+ hopefully, continue to have the new behavior and will be
+ handled based on that assumption. This option defaults to
+ the old Squid behavior, which is better for hit ratios but
+ worse for clients using IE, if they need to be able to
+ force fresh content.
+DOC_END
+
+NAME: vary_ignore_expire
+COMMENT: on|off
+TYPE: onoff
+LOC: Config.onoff.vary_ignore_expire
+DEFAULT: off
+DOC_START
+ Many HTTP servers supporting Vary gives such objects
+ immediate expiry time with no cache-control header
+ when requested by a HTTP/1.0 client. This option
+ enables Squid to ignore such expiry times until
+ HTTP/1.1 is fully implemented.
+ WARNING: This may eventually cause some varying
+ objects not intended for caching to get cached.
+DOC_END
+
+NAME: sleep_after_fork
+COMMENT: (microseconds)
+TYPE: int
+LOC: Config.sleep_after_fork
+DEFAULT: 0
+DOC_START
+ When this is set to a non-zero value, the main Squid process
+ sleeps the specified number of microseconds after a fork()
+ system call. This sleep may help the situation where your
+ system reports fork() failures due to lack of (virtual)
+ memory. Note, however, that if you have a lot of child
+ processes, these sleep delays will add up and your
+ Squid will not service requests for some amount of time
+ until all the child processes have been started.
+ On Windows value less then 1000 (1 milliseconds) are
+ rounded to 1000.
+DOC_END
+
+NAME: minimum_expiry_time
+COMMENT: (seconds)
+TYPE: time_t
+LOC: Config.minimum_expiry_time
+DEFAULT: 60 seconds
+DOC_START
+ The minimum caching time according to (Expires - Date)
+ Headers Squid honors if the object can't be revalidated
+ defaults to 60 seconds. In reverse proxy enorinments it
+ might be desirable to honor shorter object lifetimes. It
+ is most likely better to make your server return a
+ meaningful Last-Modified header however.
+DOC_END
+
+NAME: relaxed_header_parser
+COMMENT: on|off|warn
+TYPE: tristate
+LOC: Config.onoff.relaxed_header_parser
+DEFAULT: on
+DOC_START
+ In the default "on" setting Squid accepts certain forms
+ of non-compliant HTTP messages where it is unambiguous
+ what the sending application intended even if the message
+ is not correctly formatted. The messages is then normalized
+ to the correct form when forwarded by Squid.
+
+ If set to "warn" then a warning will be emitted in cache.log
+ each time such HTTP error is encountered.
+
+ If set to "off" then such HTTP errors will cause the request
+ or response to be rejected.
+DOC_END
+
+EOF
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/f7/f0fca1315c88001b16add8656805b17d squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/f7/f0fca1315c88001b16add8656805b17d
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/f7/f0fca1315c88001b16add8656805b17d 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.history/f7/f0fca1315c88001b16add8656805b17d 2006-12-10 16:10:54.000000000 +0200
@@ -0,0 +1,29 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+# Add inputs and outputs from these tool invocations to the build variables
+C_SRCS += \
+$(ROOT)/repl/lru/store_repl_lru.c
+
+OBJS += \
+./repl/lru/store_repl_lru.o
+
+DEPS += \
+${addprefix ./repl/lru/, \
+store_repl_lru.d \
+}
+
+
+# Each subdirectory must supply rules for building sources it contributes
+repl/lru/%.o: $(ROOT)/repl/lru/%.c
+ @echo 'Building file: $<'
+ @echo 'Invoking: GCC C Compiler'
+ @echo gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $<
+ @gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $< && \
+ echo -n $(@:%.o=%.d) $(dir $@) > $(@:%.o=%.d) && \
+ gcc -MM -MG -P -w -O0 -g3 -Wall -c -fmessage-length=0 $< >> $(@:%.o=%.d)
+ @echo 'Finished building: $<'
+ @echo ' '
+
+
Binary files squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.indexes/33/6f/af/history.index and squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.indexes/33/6f/af/history.index differ
Binary files squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.indexes/33/6f/ec/history.index and squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.indexes/33/6f/ec/history.index differ
Binary files squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.indexes/33/a8/2e/history.index and squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.indexes/33/a8/2e/history.index differ
Binary files squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.indexes/33/a8/3c/history.index and squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.indexes/33/a8/3c/history.index differ
Binary files squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.indexes/33/a8/82/history.index and squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.indexes/33/a8/82/history.index differ
Binary files squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.indexes/33/a8/c7/history.index and squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.indexes/33/a8/c7/history.index differ
Binary files squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.indexes/33/cd/1/history.index and squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.indexes/33/cd/1/history.index differ
Binary files squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.indexes/33/cd/2/history.index and squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.indexes/33/cd/2/history.index differ
Binary files squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.indexes/33/cd/67/history.index and squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.indexes/33/cd/67/history.index differ
Binary files squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.indexes/33/cd/87/history.index and squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.indexes/33/cd/87/history.index differ
Binary files squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.indexes/33/cd/cc/history.index and squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.indexes/33/cd/cc/history.index differ
Binary files squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.indexes/33/history.index and squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.indexes/33/history.index differ
Binary files squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.indexes/af/history.index and squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.indexes/af/history.index differ
Binary files squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.indexes/history.index and squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.indexes/history.index differ
Binary files squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.indexes/properties.index and squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.indexes/properties.index differ
Binary files squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.markers.snap and squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.markers.snap differ
Binary files squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.syncinfo.snap and squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.projects/src/.syncinfo.snap differ
Binary files squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.root/.indexes/properties.index and squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.root/.indexes/properties.index differ
Binary files squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.root/.markers.snap and squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.root/.markers.snap differ
Binary files squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.safetable/org.eclipse.core.resources and squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.safetable/org.eclipse.core.resources differ
Binary files squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.snap and squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.resources/.snap differ
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.cdt.debug.core.prefs squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.cdt.debug.core.prefs
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.cdt.debug.core.prefs 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.cdt.debug.core.prefs 2006-12-10 16:11:20.000000000 +0200
@@ -0,0 +1,3 @@
+#Sun Dec 10 16:11:20 IST 2006
+org.eclipse.cdt.debug.core.cDebug.common_source_containers=\n\n\n\n
+eclipse.preferences.version=1
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.core.resources.prefs squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.core.resources.prefs
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.core.resources.prefs 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.core.resources.prefs 2006-12-10 16:45:02.000000000 +0200
@@ -0,0 +1,4 @@
+#Sun Dec 10 16:45:02 IST 2006
+version=1
+eclipse.preferences.version=1
+description.autobuilding=false
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.prefs squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.prefs
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.prefs 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.prefs 2006-12-10 16:10:23.000000000 +0200
@@ -0,0 +1,3 @@
+#Sun Dec 10 16:10:23 IST 2006
+eclipse.preferences.version=1
+showIntro=false
diff -ruN squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.wst.server.core.prefs squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.wst.server.core.prefs
--- squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.wst.server.core.prefs 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.wst.server.core.prefs 2006-12-10 16:10:19.000000000 +0200
@@ -0,0 +1,3 @@
+#Sun Dec 10 16:10:19 IST 2006
+module-start-timeout=300000
+eclipse.preferences.version=1
Binary files squid-2.6.STABLE5/.metadata/.plugins/org.eclipse.jdt.core/variablesAndContainers.dat and squid-icap-2.6.STABLE5/.metadata/.plugins/org.eclipse.jdt.core/variablesAndContainers.dat differ
diff -ruN squid-2.6.STABLE5/.metadata/version.ini squid-icap-2.6.STABLE5/.metadata/version.ini
--- squid-2.6.STABLE5/.metadata/version.ini 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/.metadata/version.ini 2006-12-10 16:10:13.000000000 +0200
@@ -0,0 +1 @@
+org.eclipse.core.runtime=1
\ No newline at end of file
diff -ruN squid-2.6.STABLE5/PSMakefile squid-icap-2.6.STABLE5/PSMakefile
--- squid-2.6.STABLE5/PSMakefile 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/PSMakefile 2006-12-10 18:13:17.000000000 +0200
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+cat PURE_SIGHT_CONFIGURE_PARAMS | xargs ./configure
+make
+strip src/squid
+
diff -ruN squid-2.6.STABLE5/PURE_SIGHT_CONFIGURE_PARAMS squid-icap-2.6.STABLE5/PURE_SIGHT_CONFIGURE_PARAMS
--- squid-2.6.STABLE5/PURE_SIGHT_CONFIGURE_PARAMS 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/PURE_SIGHT_CONFIGURE_PARAMS 2006-12-10 18:14:21.000000000 +0200
@@ -0,0 +1 @@
+'--host=i686-pc-linux-gnu' '--build=i686-pc-linux-gnu' '--target=i386-redhat-linux-gnu' '--program-prefix=' '--prefix=/usr' '--exec-prefix=/usr' '--bindir=/usr/bin' '--sbindir=/usr/sbin' '--sysconfdir=/etc' '--datadir=/usr/share' '--includedir=/usr/include' '--libdir=/usr/lib' '--libexecdir=/usr/libexec' '--sharedstatedir=/usr/com' '--mandir=/usr/share/man' '--infodir=/usr/share/info' '--exec_prefix=/usr' '--bindir=/usr/sbin' '--libexecdir=/usr/lib/squid' '--localstatedir=/var' '--sysconfdir=/etc/squid' '--enable-poll' '--enable-snmp' '--enable-removal-policies=heap,lru' '--enable-storeio=aufs,coss,diskd,null,ufs' '--enable-ssl' '--with-openssl=/usr/kerberos' '--enable-delay-pools' '--enable-linux-netfilter' '--with-pthreads' '--enable-basic-auth-helpers=LDAP,NCSA,PAM,SMB,SASL,MSNT' '--enable-ntlm-auth-helpers=SMB,fakeauth' '--enable-external-acl-helpers=ip_user,ldap_group,unix_group,wbinfo_group' '--enable-auth=basic,ntlm' '--enable-useragent-log' '--enable-referer-log' '--enable-icap-support' 'build_alias=i686-pc-linux-gnu' 'host_alias=i686-pc-linux-gnu' 'target_alias=i386-redhat-linux-gnu'
diff -ruN squid-2.6.STABLE5/src/.cdtbuild squid-icap-2.6.STABLE5/src/.cdtbuild
--- squid-2.6.STABLE5/src/.cdtbuild 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/src/.cdtbuild 2006-12-10 16:10:49.000000000 +0200
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -ruN squid-2.6.STABLE5/src/.cdtproject squid-icap-2.6.STABLE5/src/.cdtproject
--- squid-2.6.STABLE5/src/.cdtproject 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/src/.cdtproject 2006-12-10 16:45:24.000000000 +0200
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+-
+
+
+
+
+
+
diff -ruN squid-2.6.STABLE5/src/cf.data.pre squid-icap-2.6.STABLE5/src/cf.data.pre
--- squid-2.6.STABLE5/src/cf.data.pre 2006-12-10 18:50:18.000000000 +0200
+++ squid-icap-2.6.STABLE5/src/cf.data.pre 2006-12-10 18:07:07.000000000 +0200
@@ -3632,6 +3632,55 @@
icap_access class_1 allow all
DOC_END
+NAME: icap_req_mod_direct_reply
+TYPE: onoff
+IFDEF: HS_FEAT_ICAP
+COMMENT: on|off
+LOC: Config.icapcfg.icap_req_mod_direct_reply
+DEFAULT: off
+DOC_START
+ classification based direct reply.
+ ICAP Server reply at request mod contains classification that
+ will define if the origin server reply should be send directly
+ to the client.
+ Usually used in content filtering, in case that classification is known
+ at the request mod, and there is no need to recheck at resp mod.
+DOC_END
+
+NAME: icap_req_mod_direct_reply_resp_info_tag_name
+TYPE: string
+IFDEF: HS_FEAT_ICAP
+LOC: Config.icapcfg.resp_info_tag_name
+DEFAULT: X-Response-Info
+DOC_START
+ req mod reply classification tag name
+DOC_END
+
+NAME: icap_req_mod_direct_reply_values
+TYPE: wordlist
+IFDEF: HS_FEAT_ICAP
+LOC: Config.icapcfg.icap_req_mod_direct_reply_values
+DEFAULT: ii_ALLOW_ALLOW_ii
+DOC_START
+ the values that couse a direct reply,
+ in case of a contant filter it will be any value,
+ that marks that the requested URL is valid, at
+ request mod.
+ in some cases you may know that in the request stage.
+DOC_END
+
+NAME: icap_session_context_tag_name
+TYPE: string
+IFDEF: HS_FEAT_ICAP
+LOC: Config.icapcfg.icap_session_context_tag_name
+DEFAULT: ICAP-Session-Info
+DOC_START
+ a string that will be passed in the response,
+ with the same tag name.
+Example:
+ icap_session_context_tag_name ICAP-Session-Info
+DOC_END
+
COMMENT_START
MISCELLANEOUS
-----------------------------------------------------------------------------
diff -ruN squid-2.6.STABLE5/src/Debug/auth/basic/subdir.mk squid-icap-2.6.STABLE5/src/Debug/auth/basic/subdir.mk
--- squid-2.6.STABLE5/src/Debug/auth/basic/subdir.mk 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/src/Debug/auth/basic/subdir.mk 2006-12-10 16:39:09.000000000 +0200
@@ -0,0 +1,29 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+# Add inputs and outputs from these tool invocations to the build variables
+C_SRCS += \
+$(ROOT)/auth/basic/auth_basic.c
+
+OBJS += \
+./auth/basic/auth_basic.o
+
+DEPS += \
+${addprefix ./auth/basic/, \
+auth_basic.d \
+}
+
+
+# Each subdirectory must supply rules for building sources it contributes
+auth/basic/%.o: $(ROOT)/auth/basic/%.c
+ @echo 'Building file: $<'
+ @echo 'Invoking: GCC C Compiler'
+ @echo gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $<
+ @gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $< && \
+ echo -n $(@:%.o=%.d) $(dir $@) > $(@:%.o=%.d) && \
+ gcc -MM -MG -P -w -O0 -g3 -Wall -c -fmessage-length=0 $< >> $(@:%.o=%.d)
+ @echo 'Finished building: $<'
+ @echo ' '
+
+
diff -ruN squid-2.6.STABLE5/src/Debug/auth/digest/subdir.mk squid-icap-2.6.STABLE5/src/Debug/auth/digest/subdir.mk
--- squid-2.6.STABLE5/src/Debug/auth/digest/subdir.mk 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/src/Debug/auth/digest/subdir.mk 2006-12-10 16:39:09.000000000 +0200
@@ -0,0 +1,29 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+# Add inputs and outputs from these tool invocations to the build variables
+C_SRCS += \
+$(ROOT)/auth/digest/auth_digest.c
+
+OBJS += \
+./auth/digest/auth_digest.o
+
+DEPS += \
+${addprefix ./auth/digest/, \
+auth_digest.d \
+}
+
+
+# Each subdirectory must supply rules for building sources it contributes
+auth/digest/%.o: $(ROOT)/auth/digest/%.c
+ @echo 'Building file: $<'
+ @echo 'Invoking: GCC C Compiler'
+ @echo gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $<
+ @gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $< && \
+ echo -n $(@:%.o=%.d) $(dir $@) > $(@:%.o=%.d) && \
+ gcc -MM -MG -P -w -O0 -g3 -Wall -c -fmessage-length=0 $< >> $(@:%.o=%.d)
+ @echo 'Finished building: $<'
+ @echo ' '
+
+
diff -ruN squid-2.6.STABLE5/src/Debug/auth/negotiate/subdir.mk squid-icap-2.6.STABLE5/src/Debug/auth/negotiate/subdir.mk
--- squid-2.6.STABLE5/src/Debug/auth/negotiate/subdir.mk 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/src/Debug/auth/negotiate/subdir.mk 2006-12-10 16:39:09.000000000 +0200
@@ -0,0 +1,29 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+# Add inputs and outputs from these tool invocations to the build variables
+C_SRCS += \
+$(ROOT)/auth/negotiate/auth_negotiate.c
+
+OBJS += \
+./auth/negotiate/auth_negotiate.o
+
+DEPS += \
+${addprefix ./auth/negotiate/, \
+auth_negotiate.d \
+}
+
+
+# Each subdirectory must supply rules for building sources it contributes
+auth/negotiate/%.o: $(ROOT)/auth/negotiate/%.c
+ @echo 'Building file: $<'
+ @echo 'Invoking: GCC C Compiler'
+ @echo gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $<
+ @gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $< && \
+ echo -n $(@:%.o=%.d) $(dir $@) > $(@:%.o=%.d) && \
+ gcc -MM -MG -P -w -O0 -g3 -Wall -c -fmessage-length=0 $< >> $(@:%.o=%.d)
+ @echo 'Finished building: $<'
+ @echo ' '
+
+
diff -ruN squid-2.6.STABLE5/src/Debug/auth/ntlm/subdir.mk squid-icap-2.6.STABLE5/src/Debug/auth/ntlm/subdir.mk
--- squid-2.6.STABLE5/src/Debug/auth/ntlm/subdir.mk 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/src/Debug/auth/ntlm/subdir.mk 2006-12-10 16:39:09.000000000 +0200
@@ -0,0 +1,29 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+# Add inputs and outputs from these tool invocations to the build variables
+C_SRCS += \
+$(ROOT)/auth/ntlm/auth_ntlm.c
+
+OBJS += \
+./auth/ntlm/auth_ntlm.o
+
+DEPS += \
+${addprefix ./auth/ntlm/, \
+auth_ntlm.d \
+}
+
+
+# Each subdirectory must supply rules for building sources it contributes
+auth/ntlm/%.o: $(ROOT)/auth/ntlm/%.c
+ @echo 'Building file: $<'
+ @echo 'Invoking: GCC C Compiler'
+ @echo gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $<
+ @gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $< && \
+ echo -n $(@:%.o=%.d) $(dir $@) > $(@:%.o=%.d) && \
+ gcc -MM -MG -P -w -O0 -g3 -Wall -c -fmessage-length=0 $< >> $(@:%.o=%.d)
+ @echo 'Finished building: $<'
+ @echo ' '
+
+
diff -ruN squid-2.6.STABLE5/src/Debug/fs/aufs/subdir.mk squid-icap-2.6.STABLE5/src/Debug/fs/aufs/subdir.mk
--- squid-2.6.STABLE5/src/Debug/fs/aufs/subdir.mk 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/src/Debug/fs/aufs/subdir.mk 2006-12-10 16:39:09.000000000 +0200
@@ -0,0 +1,41 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+# Add inputs and outputs from these tool invocations to the build variables
+C_SRCS += \
+$(ROOT)/fs/aufs/aiops.c \
+$(ROOT)/fs/aufs/aiops_win32.c \
+$(ROOT)/fs/aufs/async_io.c \
+$(ROOT)/fs/aufs/store_dir_aufs.c \
+$(ROOT)/fs/aufs/store_io_aufs.c
+
+OBJS += \
+./fs/aufs/aiops.o \
+./fs/aufs/aiops_win32.o \
+./fs/aufs/async_io.o \
+./fs/aufs/store_dir_aufs.o \
+./fs/aufs/store_io_aufs.o
+
+DEPS += \
+${addprefix ./fs/aufs/, \
+aiops.d \
+aiops_win32.d \
+async_io.d \
+store_dir_aufs.d \
+store_io_aufs.d \
+}
+
+
+# Each subdirectory must supply rules for building sources it contributes
+fs/aufs/%.o: $(ROOT)/fs/aufs/%.c
+ @echo 'Building file: $<'
+ @echo 'Invoking: GCC C Compiler'
+ @echo gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $<
+ @gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $< && \
+ echo -n $(@:%.o=%.d) $(dir $@) > $(@:%.o=%.d) && \
+ gcc -MM -MG -P -w -O0 -g3 -Wall -c -fmessage-length=0 $< >> $(@:%.o=%.d)
+ @echo 'Finished building: $<'
+ @echo ' '
+
+
diff -ruN squid-2.6.STABLE5/src/Debug/fs/coss/subdir.mk squid-icap-2.6.STABLE5/src/Debug/fs/coss/subdir.mk
--- squid-2.6.STABLE5/src/Debug/fs/coss/subdir.mk 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/src/Debug/fs/coss/subdir.mk 2006-12-10 16:39:09.000000000 +0200
@@ -0,0 +1,35 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+# Add inputs and outputs from these tool invocations to the build variables
+C_SRCS += \
+$(ROOT)/fs/coss/async_io.c \
+$(ROOT)/fs/coss/store_dir_coss.c \
+$(ROOT)/fs/coss/store_io_coss.c
+
+OBJS += \
+./fs/coss/async_io.o \
+./fs/coss/store_dir_coss.o \
+./fs/coss/store_io_coss.o
+
+DEPS += \
+${addprefix ./fs/coss/, \
+async_io.d \
+store_dir_coss.d \
+store_io_coss.d \
+}
+
+
+# Each subdirectory must supply rules for building sources it contributes
+fs/coss/%.o: $(ROOT)/fs/coss/%.c
+ @echo 'Building file: $<'
+ @echo 'Invoking: GCC C Compiler'
+ @echo gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $<
+ @gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $< && \
+ echo -n $(@:%.o=%.d) $(dir $@) > $(@:%.o=%.d) && \
+ gcc -MM -MG -P -w -O0 -g3 -Wall -c -fmessage-length=0 $< >> $(@:%.o=%.d)
+ @echo 'Finished building: $<'
+ @echo ' '
+
+
diff -ruN squid-2.6.STABLE5/src/Debug/fs/diskd/subdir.mk squid-icap-2.6.STABLE5/src/Debug/fs/diskd/subdir.mk
--- squid-2.6.STABLE5/src/Debug/fs/diskd/subdir.mk 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/src/Debug/fs/diskd/subdir.mk 2006-12-10 16:39:09.000000000 +0200
@@ -0,0 +1,35 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+# Add inputs and outputs from these tool invocations to the build variables
+C_SRCS += \
+$(ROOT)/fs/diskd/diskd.c \
+$(ROOT)/fs/diskd/store_dir_diskd.c \
+$(ROOT)/fs/diskd/store_io_diskd.c
+
+OBJS += \
+./fs/diskd/diskd.o \
+./fs/diskd/store_dir_diskd.o \
+./fs/diskd/store_io_diskd.o
+
+DEPS += \
+${addprefix ./fs/diskd/, \
+diskd.d \
+store_dir_diskd.d \
+store_io_diskd.d \
+}
+
+
+# Each subdirectory must supply rules for building sources it contributes
+fs/diskd/%.o: $(ROOT)/fs/diskd/%.c
+ @echo 'Building file: $<'
+ @echo 'Invoking: GCC C Compiler'
+ @echo gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $<
+ @gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $< && \
+ echo -n $(@:%.o=%.d) $(dir $@) > $(@:%.o=%.d) && \
+ gcc -MM -MG -P -w -O0 -g3 -Wall -c -fmessage-length=0 $< >> $(@:%.o=%.d)
+ @echo 'Finished building: $<'
+ @echo ' '
+
+
diff -ruN squid-2.6.STABLE5/src/Debug/fs/null/subdir.mk squid-icap-2.6.STABLE5/src/Debug/fs/null/subdir.mk
--- squid-2.6.STABLE5/src/Debug/fs/null/subdir.mk 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/src/Debug/fs/null/subdir.mk 2006-12-10 16:39:09.000000000 +0200
@@ -0,0 +1,29 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+# Add inputs and outputs from these tool invocations to the build variables
+C_SRCS += \
+$(ROOT)/fs/null/store_null.c
+
+OBJS += \
+./fs/null/store_null.o
+
+DEPS += \
+${addprefix ./fs/null/, \
+store_null.d \
+}
+
+
+# Each subdirectory must supply rules for building sources it contributes
+fs/null/%.o: $(ROOT)/fs/null/%.c
+ @echo 'Building file: $<'
+ @echo 'Invoking: GCC C Compiler'
+ @echo gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $<
+ @gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $< && \
+ echo -n $(@:%.o=%.d) $(dir $@) > $(@:%.o=%.d) && \
+ gcc -MM -MG -P -w -O0 -g3 -Wall -c -fmessage-length=0 $< >> $(@:%.o=%.d)
+ @echo 'Finished building: $<'
+ @echo ' '
+
+
diff -ruN squid-2.6.STABLE5/src/Debug/fs/ufs/subdir.mk squid-icap-2.6.STABLE5/src/Debug/fs/ufs/subdir.mk
--- squid-2.6.STABLE5/src/Debug/fs/ufs/subdir.mk 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/src/Debug/fs/ufs/subdir.mk 2006-12-10 16:39:09.000000000 +0200
@@ -0,0 +1,32 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+# Add inputs and outputs from these tool invocations to the build variables
+C_SRCS += \
+$(ROOT)/fs/ufs/store_dir_ufs.c \
+$(ROOT)/fs/ufs/store_io_ufs.c
+
+OBJS += \
+./fs/ufs/store_dir_ufs.o \
+./fs/ufs/store_io_ufs.o
+
+DEPS += \
+${addprefix ./fs/ufs/, \
+store_dir_ufs.d \
+store_io_ufs.d \
+}
+
+
+# Each subdirectory must supply rules for building sources it contributes
+fs/ufs/%.o: $(ROOT)/fs/ufs/%.c
+ @echo 'Building file: $<'
+ @echo 'Invoking: GCC C Compiler'
+ @echo gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $<
+ @gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $< && \
+ echo -n $(@:%.o=%.d) $(dir $@) > $(@:%.o=%.d) && \
+ gcc -MM -MG -P -w -O0 -g3 -Wall -c -fmessage-length=0 $< >> $(@:%.o=%.d)
+ @echo 'Finished building: $<'
+ @echo ' '
+
+
diff -ruN squid-2.6.STABLE5/src/Debug/makefile squid-icap-2.6.STABLE5/src/Debug/makefile
--- squid-2.6.STABLE5/src/Debug/makefile 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/src/Debug/makefile 2006-12-10 16:39:09.000000000 +0200
@@ -0,0 +1,43 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+ROOT := ..
+
+-include $(ROOT)/makefile.init
+
+RM := rm -rf
+
+# All of the sources participating in the build are defined here
+-include sources.mk
+-include $(SUBDIRS:%=%/subdir.mk)
+-include objects.mk
+ifneq ($(strip $(DEPS)),)
+-include $(DEPS)
+endif
+
+-include $(ROOT)/makefile.defs
+
+# Add inputs and outputs from these tool invocations to the build variables
+
+# All Target
+all: src
+
+# Tool invocations
+src: $(OBJS) $(USER_OBJS)
+ @echo 'Building target: $@'
+ @echo 'Invoking: GCC C Linker'
+ @echo gcc -osrc $(OBJS) $(USER_OBJS) $(LIBS)
+ @gcc -osrc $(OBJS) $(USER_OBJS) $(LIBS)
+ @echo 'Finished building target: $@'
+ @echo ' '
+
+# Other Targets
+clean:
+ -$(RM) $(OBJS)$(DEPS)$(EXECUTABLES) src
+ -@echo ' '
+
+.PHONY: all clean dependents
+.SECONDARY:
+
+-include $(ROOT)/makefile.targets
diff -ruN squid-2.6.STABLE5/src/Debug/objects.mk squid-icap-2.6.STABLE5/src/Debug/objects.mk
--- squid-2.6.STABLE5/src/Debug/objects.mk 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/src/Debug/objects.mk 2006-12-10 16:10:54.000000000 +0200
@@ -0,0 +1,7 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+LIBS :=
+
+USER_OBJS :=
\ No newline at end of file
diff -ruN squid-2.6.STABLE5/src/Debug/repl/heap/subdir.mk squid-icap-2.6.STABLE5/src/Debug/repl/heap/subdir.mk
--- squid-2.6.STABLE5/src/Debug/repl/heap/subdir.mk 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/src/Debug/repl/heap/subdir.mk 2006-12-10 16:39:08.000000000 +0200
@@ -0,0 +1,32 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+# Add inputs and outputs from these tool invocations to the build variables
+C_SRCS += \
+$(ROOT)/repl/heap/store_heap_replacement.c \
+$(ROOT)/repl/heap/store_repl_heap.c
+
+OBJS += \
+./repl/heap/store_heap_replacement.o \
+./repl/heap/store_repl_heap.o
+
+DEPS += \
+${addprefix ./repl/heap/, \
+store_heap_replacement.d \
+store_repl_heap.d \
+}
+
+
+# Each subdirectory must supply rules for building sources it contributes
+repl/heap/%.o: $(ROOT)/repl/heap/%.c
+ @echo 'Building file: $<'
+ @echo 'Invoking: GCC C Compiler'
+ @echo gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $<
+ @gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $< && \
+ echo -n $(@:%.o=%.d) $(dir $@) > $(@:%.o=%.d) && \
+ gcc -MM -MG -P -w -O0 -g3 -Wall -c -fmessage-length=0 $< >> $(@:%.o=%.d)
+ @echo 'Finished building: $<'
+ @echo ' '
+
+
diff -ruN squid-2.6.STABLE5/src/Debug/repl/lru/subdir.mk squid-icap-2.6.STABLE5/src/Debug/repl/lru/subdir.mk
--- squid-2.6.STABLE5/src/Debug/repl/lru/subdir.mk 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/src/Debug/repl/lru/subdir.mk 2006-12-10 16:39:08.000000000 +0200
@@ -0,0 +1,29 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+# Add inputs and outputs from these tool invocations to the build variables
+C_SRCS += \
+$(ROOT)/repl/lru/store_repl_lru.c
+
+OBJS += \
+./repl/lru/store_repl_lru.o
+
+DEPS += \
+${addprefix ./repl/lru/, \
+store_repl_lru.d \
+}
+
+
+# Each subdirectory must supply rules for building sources it contributes
+repl/lru/%.o: $(ROOT)/repl/lru/%.c
+ @echo 'Building file: $<'
+ @echo 'Invoking: GCC C Compiler'
+ @echo gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $<
+ @gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $< && \
+ echo -n $(@:%.o=%.d) $(dir $@) > $(@:%.o=%.d) && \
+ gcc -MM -MG -P -w -O0 -g3 -Wall -c -fmessage-length=0 $< >> $(@:%.o=%.d)
+ @echo 'Finished building: $<'
+ @echo ' '
+
+
diff -ruN squid-2.6.STABLE5/src/Debug/sources.mk squid-icap-2.6.STABLE5/src/Debug/sources.mk
--- squid-2.6.STABLE5/src/Debug/sources.mk 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/src/Debug/sources.mk 2006-12-10 16:39:08.000000000 +0200
@@ -0,0 +1,28 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+C_SRCS :=
+O_SRCS :=
+ASM_SRCS :=
+S_SRCS :=
+OBJ_SRCS :=
+OBJS :=
+DEPS :=
+EXECUTABLES :=
+
+# Every subdirectory with source files must be described here
+SUBDIRS := \
+. \
+repl/lru \
+repl/heap \
+fs/ufs \
+fs/null \
+fs/diskd \
+fs/coss \
+fs/aufs \
+auth/ntlm \
+auth/negotiate \
+auth/digest \
+auth/basic \
+
diff -ruN squid-2.6.STABLE5/src/Debug/subdir.mk squid-icap-2.6.STABLE5/src/Debug/subdir.mk
--- squid-2.6.STABLE5/src/Debug/subdir.mk 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/src/Debug/subdir.mk 2006-12-10 16:39:08.000000000 +0200
@@ -0,0 +1,365 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+# Add inputs and outputs from these tool invocations to the build variables
+C_SRCS += \
+$(ROOT)/CacheDigest.c \
+$(ROOT)/HttpBody.c \
+$(ROOT)/HttpHdrCc.c \
+$(ROOT)/HttpHdrContRange.c \
+$(ROOT)/HttpHdrRange.c \
+$(ROOT)/HttpHeader.c \
+$(ROOT)/HttpHeaderTools.c \
+$(ROOT)/HttpMsg.c \
+$(ROOT)/HttpReply.c \
+$(ROOT)/HttpRequest.c \
+$(ROOT)/HttpStatusLine.c \
+$(ROOT)/MemBuf.c \
+$(ROOT)/MemPool.c \
+$(ROOT)/Packer.c \
+$(ROOT)/StatHist.c \
+$(ROOT)/String.c \
+$(ROOT)/access_log.c \
+$(ROOT)/acl.c \
+$(ROOT)/asn.c \
+$(ROOT)/authenticate.c \
+$(ROOT)/cache_cf.c \
+$(ROOT)/cache_manager.c \
+$(ROOT)/carp.c \
+$(ROOT)/cbdata.c \
+$(ROOT)/cf_gen.c \
+$(ROOT)/client_db.c \
+$(ROOT)/client_side.c \
+$(ROOT)/comm.c \
+$(ROOT)/comm_epoll.c \
+$(ROOT)/comm_generic.c \
+$(ROOT)/comm_kqueue.c \
+$(ROOT)/comm_poll.c \
+$(ROOT)/comm_select.c \
+$(ROOT)/comm_select_simple.c \
+$(ROOT)/comm_select_win32.c \
+$(ROOT)/debug.c \
+$(ROOT)/delay_pools.c \
+$(ROOT)/disk.c \
+$(ROOT)/dns.c \
+$(ROOT)/dns_internal.c \
+$(ROOT)/dnsserver.c \
+$(ROOT)/errormap.c \
+$(ROOT)/errorpage.c \
+$(ROOT)/event.c \
+$(ROOT)/external_acl.c \
+$(ROOT)/fd.c \
+$(ROOT)/filemap.c \
+$(ROOT)/forward.c \
+$(ROOT)/fqdncache.c \
+$(ROOT)/ftp.c \
+$(ROOT)/gopher.c \
+$(ROOT)/helper.c \
+$(ROOT)/htcp.c \
+$(ROOT)/http.c \
+$(ROOT)/icap_common.c \
+$(ROOT)/icap_opt.c \
+$(ROOT)/icap_reqmod.c \
+$(ROOT)/icap_respmod.c \
+$(ROOT)/icmp.c \
+$(ROOT)/icp_v2.c \
+$(ROOT)/icp_v3.c \
+$(ROOT)/ident.c \
+$(ROOT)/internal.c \
+$(ROOT)/ipc.c \
+$(ROOT)/ipc_win32.c \
+$(ROOT)/ipcache.c \
+$(ROOT)/leakfinder.c \
+$(ROOT)/locrewrite.c \
+$(ROOT)/logfile.c \
+$(ROOT)/main.c \
+$(ROOT)/mem.c \
+$(ROOT)/mime.c \
+$(ROOT)/multicast.c \
+$(ROOT)/neighbors.c \
+$(ROOT)/net_db.c \
+$(ROOT)/pconn.c \
+$(ROOT)/peer_digest.c \
+$(ROOT)/peer_monitor.c \
+$(ROOT)/peer_select.c \
+$(ROOT)/peer_sourcehash.c \
+$(ROOT)/peer_userhash.c \
+$(ROOT)/pinger.c \
+$(ROOT)/redirect.c \
+$(ROOT)/referer.c \
+$(ROOT)/refresh.c \
+$(ROOT)/send-announce.c \
+$(ROOT)/snmp_agent.c \
+$(ROOT)/snmp_core.c \
+$(ROOT)/ssl.c \
+$(ROOT)/ssl_support.c \
+$(ROOT)/stat.c \
+$(ROOT)/stmem.c \
+$(ROOT)/store.c \
+$(ROOT)/store_client.c \
+$(ROOT)/store_digest.c \
+$(ROOT)/store_dir.c \
+$(ROOT)/store_io.c \
+$(ROOT)/store_key_md5.c \
+$(ROOT)/store_log.c \
+$(ROOT)/store_rebuild.c \
+$(ROOT)/store_swapin.c \
+$(ROOT)/store_swapmeta.c \
+$(ROOT)/store_swapout.c \
+$(ROOT)/tools.c \
+$(ROOT)/unlinkd.c \
+$(ROOT)/url.c \
+$(ROOT)/urn.c \
+$(ROOT)/useragent.c \
+$(ROOT)/wais.c \
+$(ROOT)/wccp.c \
+$(ROOT)/wccp2.c \
+$(ROOT)/whois.c \
+$(ROOT)/win32.c
+
+OBJS += \
+./CacheDigest.o \
+./HttpBody.o \
+./HttpHdrCc.o \
+./HttpHdrContRange.o \
+./HttpHdrRange.o \
+./HttpHeader.o \
+./HttpHeaderTools.o \
+./HttpMsg.o \
+./HttpReply.o \
+./HttpRequest.o \
+./HttpStatusLine.o \
+./MemBuf.o \
+./MemPool.o \
+./Packer.o \
+./StatHist.o \
+./String.o \
+./access_log.o \
+./acl.o \
+./asn.o \
+./authenticate.o \
+./cache_cf.o \
+./cache_manager.o \
+./carp.o \
+./cbdata.o \
+./cf_gen.o \
+./client_db.o \
+./client_side.o \
+./comm.o \
+./comm_epoll.o \
+./comm_generic.o \
+./comm_kqueue.o \
+./comm_poll.o \
+./comm_select.o \
+./comm_select_simple.o \
+./comm_select_win32.o \
+./debug.o \
+./delay_pools.o \
+./disk.o \
+./dns.o \
+./dns_internal.o \
+./dnsserver.o \
+./errormap.o \
+./errorpage.o \
+./event.o \
+./external_acl.o \
+./fd.o \
+./filemap.o \
+./forward.o \
+./fqdncache.o \
+./ftp.o \
+./gopher.o \
+./helper.o \
+./htcp.o \
+./http.o \
+./icap_common.o \
+./icap_opt.o \
+./icap_reqmod.o \
+./icap_respmod.o \
+./icmp.o \
+./icp_v2.o \
+./icp_v3.o \
+./ident.o \
+./internal.o \
+./ipc.o \
+./ipc_win32.o \
+./ipcache.o \
+./leakfinder.o \
+./locrewrite.o \
+./logfile.o \
+./main.o \
+./mem.o \
+./mime.o \
+./multicast.o \
+./neighbors.o \
+./net_db.o \
+./pconn.o \
+./peer_digest.o \
+./peer_monitor.o \
+./peer_select.o \
+./peer_sourcehash.o \
+./peer_userhash.o \
+./pinger.o \
+./redirect.o \
+./referer.o \
+./refresh.o \
+./send-announce.o \
+./snmp_agent.o \
+./snmp_core.o \
+./ssl.o \
+./ssl_support.o \
+./stat.o \
+./stmem.o \
+./store.o \
+./store_client.o \
+./store_digest.o \
+./store_dir.o \
+./store_io.o \
+./store_key_md5.o \
+./store_log.o \
+./store_rebuild.o \
+./store_swapin.o \
+./store_swapmeta.o \
+./store_swapout.o \
+./tools.o \
+./unlinkd.o \
+./url.o \
+./urn.o \
+./useragent.o \
+./wais.o \
+./wccp.o \
+./wccp2.o \
+./whois.o \
+./win32.o
+
+DEPS += \
+${addprefix ./, \
+CacheDigest.d \
+HttpBody.d \
+HttpHdrCc.d \
+HttpHdrContRange.d \
+HttpHdrRange.d \
+HttpHeader.d \
+HttpHeaderTools.d \
+HttpMsg.d \
+HttpReply.d \
+HttpRequest.d \
+HttpStatusLine.d \
+MemBuf.d \
+MemPool.d \
+Packer.d \
+StatHist.d \
+String.d \
+access_log.d \
+acl.d \
+asn.d \
+authenticate.d \
+cache_cf.d \
+cache_manager.d \
+carp.d \
+cbdata.d \
+cf_gen.d \
+client_db.d \
+client_side.d \
+comm.d \
+comm_epoll.d \
+comm_generic.d \
+comm_kqueue.d \
+comm_poll.d \
+comm_select.d \
+comm_select_simple.d \
+comm_select_win32.d \
+debug.d \
+delay_pools.d \
+disk.d \
+dns.d \
+dns_internal.d \
+dnsserver.d \
+errormap.d \
+errorpage.d \
+event.d \
+external_acl.d \
+fd.d \
+filemap.d \
+forward.d \
+fqdncache.d \
+ftp.d \
+gopher.d \
+helper.d \
+htcp.d \
+http.d \
+icap_common.d \
+icap_opt.d \
+icap_reqmod.d \
+icap_respmod.d \
+icmp.d \
+icp_v2.d \
+icp_v3.d \
+ident.d \
+internal.d \
+ipc.d \
+ipc_win32.d \
+ipcache.d \
+leakfinder.d \
+locrewrite.d \
+logfile.d \
+main.d \
+mem.d \
+mime.d \
+multicast.d \
+neighbors.d \
+net_db.d \
+pconn.d \
+peer_digest.d \
+peer_monitor.d \
+peer_select.d \
+peer_sourcehash.d \
+peer_userhash.d \
+pinger.d \
+redirect.d \
+referer.d \
+refresh.d \
+send-announce.d \
+snmp_agent.d \
+snmp_core.d \
+ssl.d \
+ssl_support.d \
+stat.d \
+stmem.d \
+store.d \
+store_client.d \
+store_digest.d \
+store_dir.d \
+store_io.d \
+store_key_md5.d \
+store_log.d \
+store_rebuild.d \
+store_swapin.d \
+store_swapmeta.d \
+store_swapout.d \
+tools.d \
+unlinkd.d \
+url.d \
+urn.d \
+useragent.d \
+wais.d \
+wccp.d \
+wccp2.d \
+whois.d \
+win32.d \
+}
+
+
+# Each subdirectory must supply rules for building sources it contributes
+%.o: $(ROOT)/%.c
+ @echo 'Building file: $<'
+ @echo 'Invoking: GCC C Compiler'
+ @echo gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $<
+ @gcc -O0 -g3 -Wall -c -fmessage-length=0 -o$@ $< && \
+ echo -n $(@:%.o=%.d) $(dir $@) > $(@:%.o=%.d) && \
+ gcc -MM -MG -P -w -O0 -g3 -Wall -c -fmessage-length=0 $< >> $(@:%.o=%.d)
+ @echo 'Finished building: $<'
+ @echo ' '
+
+
diff -ruN squid-2.6.STABLE5/src/http.c squid-icap-2.6.STABLE5/src/http.c
--- squid-2.6.STABLE5/src/http.c 2006-12-10 18:50:18.000000000 +0200
+++ squid-icap-2.6.STABLE5/src/http.c 2006-12-10 16:57:56.000000000 +0200
@@ -1025,7 +1025,9 @@
httpState->icap_writer = icapRespModStart(
ICAP_SERVICE_RESPMOD_PRECACHE,
httpState->orig_request, httpState->entry, httpState->flags);
- if (-1 == (int) httpState->icap_writer) {
+ if (-2 == (int) httpState->icap_writer) { // no need to call respmod
+ httpState->icap_writer = 0;
+ } else if (-1 == (int) httpState->icap_writer) {
/* TODO: send error here and exit */
ErrorState *err;
httpState->icap_writer = 0;
@@ -1566,6 +1568,10 @@
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 == -2 )
+ httpState->icap_writer = 0;
+
if (httpState->icap_writer) {
return;
}
diff -ruN squid-2.6.STABLE5/src/icap_common.c squid-icap-2.6.STABLE5/src/icap_common.c
--- squid-2.6.STABLE5/src/icap_common.c 2006-12-10 18:50:18.000000000 +0200
+++ squid-icap-2.6.STABLE5/src/icap_common.c 2006-12-10 17:00:46.000000000 +0200
@@ -261,7 +261,7 @@
icap->enc.null_body = -1;
icap->chunk_size = -1;
memBufDefInit(&icap->icap_hdr);
-
+ cap->respmod.icap_server_session_context = NULL;
debug(81, 3) ("New ICAP state\n");
return icap;
}
@@ -284,6 +284,12 @@
storeUnlockObject(icap->respmod.entry);
icap->respmod.entry = NULL;
}
+ if( icap->respmod.icap_server_session_context )
+ {
+ void *p = icap->respmod.icap_server_session_context;
+ xfree( p );
+ icap->respmod.icap_server_session_context = NULL;
+ }
requestUnlink(icap->request);
icap->request = NULL;
if (!memBufIsNull(&icap->icap_hdr))
diff -ruN squid-2.6.STABLE5/src/icap_opt.c squid-icap-2.6.STABLE5/src/icap_opt.c
--- squid-2.6.STABLE5/src/icap_opt.c 2006-12-10 18:50:18.000000000 +0200
+++ squid-icap-2.6.STABLE5/src/icap_opt.c 2006-12-10 18:09:21.000000000 +0200
@@ -517,7 +517,9 @@
icapOptDataFree(IcapOptData * i)
{
if (i) {
+ if( i->buf) { // condition added by moshe beeri, potential crash
memFreeBuf(i->size, i->buf);
memFree(i, MEM_ICAP_OPT_DATA);
}
+ }
}
diff -ruN squid-2.6.STABLE5/src/icap_reqmod.c squid-icap-2.6.STABLE5/src/icap_reqmod.c
--- squid-2.6.STABLE5/src/icap_reqmod.c 2006-12-10 18:50:18.000000000 +0200
+++ squid-icap-2.6.STABLE5/src/icap_reqmod.c 2006-12-10 16:39:08.000000000 +0200
@@ -568,6 +568,84 @@
return;
}
icapSetKeepAlive(icap, icap->icap_hdr.buf);
+
+ int icap_direct_response = 0;
+
+ if( Config.icapcfg.icap_req_mod_direct_reply == 1 )
+ {
+ debug(81, 5)( "PSICAP Config.icapcfg.icap_req_mod_direct_reply = 1\n" );
+ debug(81, 5)( "PSICAP Config.icapcfg.resp_info_tag_name=[%s]\n", Config.icapcfg.resp_info_tag_name );
+ if (icapFindHeader(icap->icap_hdr.buf, Config.icapcfg.resp_info_tag_name, &start, &end)) {
+ wordlist *w = NULL;
+ char buf[256];
+ buf[end-start] = '\0';
+ strncpy(buf,start, end-start);
+ icap_direct_response = 0;
+
+ debug(81, 5)( "PSICAP %s was found [%s]\n",Config.icapcfg.resp_info_tag_name,buf );
+
+ if ((w = Config.icapcfg.icap_req_mod_direct_reply_values) != NULL)
+ {
+ for (; w; w = w->next){
+ if ( w->key != NULL ){
+ debug(81, 5)( "PSICAP testing key [%s]\n", w->key );
+ if( strstr( buf + strlen(Config.icapcfg.resp_info_tag_name) + 1, w->key ) != NULL ){
+
+ debug(81, 5)( "PSICAP key found [%s]\n", w->key );
+
+ // we have the direct reply value, no need to check for more, just break
+ icap_direct_response = 1;
+ break;
+ }
+ }
+ }
+ debug(81, 5)( "\n");
+ }
+ }
+ }
+
+ fde *F = &fd_table[icap->reqmod.client_fd];
+
+ F->context_salt = CONTEXT_SALT;
+
+ F->icap_server_session_context = NULL;
+ debug(81, 5)( "PSICAP icap_direct_response %d\n",icap_direct_response);
+ F->icap_response_info = icap_direct_response;
+ //set the data that need to be passed from req mod replay to resp mod request
+ debug(81, 5)( "PSICAP icap_conext_debug looking for tag %s \n",Config.icapcfg.icap_session_context_tag_name);
+ if ((F->icap_response_info != 1 )
+ &&
+ (icapFindHeader(icap->icap_hdr.buf, Config.icapcfg.icap_session_context_tag_name, &start, &end)) )
+ {
+ debug(81, 5)( "PSICAP icap_conext_debug tag [%s] was found... \n", Config.icapcfg.icap_session_context_tag_name );
+ //copy the string to fde
+ int info_length = end-start;
+ if( info_length > 0 )
+ {
+ if( F->icap_server_session_context != NULL )
+ {
+ xfree( F->icap_server_session_context );
+ F->icap_server_session_context = NULL;
+ }
+ int tag_len = strlen( Config.icapcfg.icap_session_context_tag_name );
+ int additionat_len = 2; //2=strlen( ": " );
+ int context_len = info_length - tag_len - additionat_len;
+ if( context_len > 0 )
+ {
+ F->icap_server_session_context = xmalloc(context_len+1);
+ strncpy( F->icap_server_session_context,
+ start + tag_len + additionat_len,
+ context_len );
+ F->icap_server_session_context[context_len] = '\0';
+ debug(81, 5)( "PSICAP icap_conext_debug context is [%s]\n",F->icap_server_session_context );
+ }
+
+ }
+ else
+ {
+ debug(81, 5)( "PSICAP icap_conext_debug context length is 0" );
+ }
+ }
if (icapFindHeader(icap->icap_hdr.buf, "Encapsulated:", &start, &end)) {
icapParseEncapsulated(icap, start, end);
} else {
diff -ruN squid-2.6.STABLE5/src/icap_respmod.c squid-icap-2.6.STABLE5/src/icap_respmod.c
--- squid-2.6.STABLE5/src/icap_respmod.c 2006-12-10 18:50:18.000000000 +0200
+++ squid-icap-2.6.STABLE5/src/icap_respmod.c 2006-12-10 17:09:04.000000000 +0200
@@ -64,6 +64,14 @@
if (service->flags.need_x_client_ip && Config.icapcfg.send_client_ip) {
memBufPrintf(mb, "X-Client-IP: %s\r\n", client_addr);
}
+ if (icap->respmod.icap_server_session_context != NULL )
+ {
+ debug(81, 5)( "sending icap context to server %s: %s\r\n",
+ Config.icapcfg.icap_session_context_tag_name,
+ icap->respmod.icap_server_session_context);
+ memBufPrintf(mb, "%s: %s\r\n", Config.icapcfg.icap_session_context_tag_name,
+ icap->respmod.icap_server_session_context);
+ }
if (service->flags.need_x_server_ip && Config.icapcfg.send_server_ip)
icapAddOriginIP(mb, icap->request->host);
@@ -710,6 +718,54 @@
return (IcapStateData *) - 1;
}
}
+
+ int i = 0;
+ MemObject *mem = entry->mem_obj;
+ store_client *sc;
+ dlink_node *nx = NULL;
+ dlink_node *node;
+ int client_fd = -1;
+
+ // walk the entire list looking for valid callbacks, and get the http client fd
+ for (node = mem->clients.head; node; node = nx) {
+ sc = node->data;
+ nx = node->next;
+ if (sc->callback_data == NULL)
+ continue;
+// if (sc->callback == NULL)
+// continue;
+// if (sc->flags.disk_io_pending)
+// continue;
+ clientHttpRequest *http = sc->callback_data;
+ ConnStateData *conn = http->conn;
+ client_fd = conn->fd;
+
+ debug(81, 6)( "fd found at icapRespModStart %d\n", client_fd );
+ }
+
+ //check to see if there is need to use ICAP resp mod at all
+ fde *F = NULL;
+ if( client_fd > 0 )
+ {
+ F = &fd_table[client_fd];
+ debug(81, 5)( "icapRespModStart fd_table[fd=%d] icap_response_info=%d \n", client_fd, F->icap_response_info);
+
+ if( F->icap_response_info == 1 )
+ {
+ // go direct, context is not needed any longer
+ if( F->icap_server_session_context != NULL )
+ {
+ xfree( F->icap_server_session_context );
+ F->icap_server_session_context = NULL;
+ }
+ //zero thr direct respose flag.
+ F->icap_response_info = 0;
+ debug(81, 6)( "goint direct on client_fd %d\n", client_fd );
+ return (IcapStateData *) -2;
+ }
+ }
+
+
switch (type) {
/* TODO: When we support more than ICAP_SERVICE_RESPMOD_PRECACHE, we needs to change
* this switch, because callbacks isn't keep */
@@ -727,6 +783,23 @@
debug(81, 3) ("icapRespModStart: icapAllocate() failed\n");
return NULL;
}
+ if( F != NULL )
+ {
+ //for safty check the salt if it is not well, null the context.
+ if( F->context_salt != 0xABCDABCD )
+ F->icap_server_session_context = NULL;
+
+ //4 Debug
+ if( F->icap_server_session_context != NULL )
+ {
+ debug(81, 6)( "info %s: %s\r\n", Config.icapcfg.icap_session_context_tag_name,
+ F->icap_server_session_context);
+ debug(81, 6)( "context ok on client_fd %d\n", client_fd );
+ }
+ icap->respmod.icap_server_session_context = F->icap_server_session_context;
+ F->icap_server_session_context = NULL;
+ }
+
icap->request = requestLink(request);
icap->respmod.entry = entry;
if (entry)
diff -ruN squid-2.6.STABLE5/src/main.c squid-icap-2.6.STABLE5/src/main.c
--- squid-2.6.STABLE5/src/main.c 2006-12-10 18:50:18.000000000 +0200
+++ squid-icap-2.6.STABLE5/src/main.c 2006-12-10 18:04:59.000000000 +0200
@@ -260,7 +260,7 @@
icpPortNumOverride = 0;
break;
case 'v':
- printf("Squid Cache: Version %s\nconfigure options: %s\n", version_string, SQUID_CONFIGURE_OPTIONS);
+ printf("Squid Cache: Version %s\nPureSight: ICAP Enabled v 1.26.0\nconfigure options: %s\n", version_string, SQUID_CONFIGURE_OPTIONS);
#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
printf("Compiled as Windows System Service.\n");
#endif
diff -ruN squid-2.6.STABLE5/src/.project squid-icap-2.6.STABLE5/src/.project
--- squid-2.6.STABLE5/src/.project 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/src/.project 2006-12-10 16:10:49.000000000 +0200
@@ -0,0 +1,18 @@
+
+
+ src
+
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.genmakebuilder
+
+
+
+
+
+ org.eclipse.cdt.core.cnature
+ org.eclipse.cdt.managedbuilder.core.managedBuildNature
+
+
diff -ruN squid-2.6.STABLE5/src/.settings/org.eclipse.cdt.managedbuilder.core.prefs squid-icap-2.6.STABLE5/src/.settings/org.eclipse.cdt.managedbuilder.core.prefs
--- squid-2.6.STABLE5/src/.settings/org.eclipse.cdt.managedbuilder.core.prefs 1970-01-01 02:00:00.000000000 +0200
+++ squid-icap-2.6.STABLE5/src/.settings/org.eclipse.cdt.managedbuilder.core.prefs 2006-12-10 16:10:54.000000000 +0200
@@ -0,0 +1,4 @@
+#Sun Dec 10 16:10:54 IST 2006
+eclipse.preferences.version=1
+environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.debug.1102957643=\n\n\n\n\n
+environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.exe.debug.1102957643=\n\n\n\n
diff -ruN squid-2.6.STABLE5/src/structs.h squid-icap-2.6.STABLE5/src/structs.h
--- squid-2.6.STABLE5/src/structs.h 2006-12-10 18:50:18.000000000 +0200
+++ squid-icap-2.6.STABLE5/src/structs.h 2006-12-10 18:02:19.000000000 +0200
@@ -436,6 +436,11 @@
int send_server_ip;
int send_auth_user;
char *auth_scheme;
+ int icap_req_mod_direct_reply; /*onoff*/
+ char *resp_info_tag_name; /*icap tag name, that represents the response info*/
+ wordlist *icap_req_mod_direct_reply_values; /*what values */
+ char *icap_session_context_tag_name; /*tag name that will mark the session data*/
+
};
#endif /* HS_FEAT_ICAP */
@@ -885,6 +890,8 @@
int weak; /* true if it is a weak validator */
};
+#define CONTEXT_SALT 0xABCDABCD;
+
struct _fde {
unsigned int type;
u_short local_port;
@@ -948,6 +955,9 @@
#if DELAY_POOLS
int slow_id;
#endif
+ char *icap_server_session_context;
+ unsigned int context_salt;
+
};
struct _fileMap {
@@ -1165,6 +1175,7 @@
MemBuf req_hdr_copy; /* XXX barf */
MemBuf resp_copy; /* XXX barf^max */
squid_off_t res_body_sz;
+ char *icap_server_session_context;
} respmod;
struct {
unsigned int connect_requested:1;