diff options
Diffstat (limited to 'www/squid27/files/icap-2.5-core.patch')
-rw-r--r-- | www/squid27/files/icap-2.5-core.patch | 7022 |
1 files changed, 0 insertions, 7022 deletions
diff --git a/www/squid27/files/icap-2.5-core.patch b/www/squid27/files/icap-2.5-core.patch deleted file mode 100644 index 4e50207f2029..000000000000 --- a/www/squid27/files/icap-2.5-core.patch +++ /dev/null @@ -1,7022 +0,0 @@ -Patch 1 of 2 to integrate the icap-2_5 branch into the FreeBSD squid port. - -Created by Thomas-Martin Seck <tmseck@netcologne.de>. - -This patch only contains the parts of the original patchset that -actually implement the ICAP client functionality. The updates to -the build infrastructure are omitted to avoid the need to run an -autotools bootstrap. Instead, we simulate said bootstrapping with -a second patch, icap-2.5-bootstrap.patch. - -The patchset was pulled from the project's CVS repository -at cvs.devel.squid-cache.org using - -cvs diff -u -b -N -kk -rs2_5 -ricap-2_5 - -See also -<http://devel.squid-cache.org/cgi-bin/diff2/icap-2_5.patch?s2_5> -for the "official" auto-generated patchset. - -See http://devel.squid-cache.org/icap/ for further information -about the ICAP client project. - -Patch last updated: 2005-12-17 - -Index: errors/Bulgarian/ERR_ICAP_FAILURE -=================================================================== -RCS file: errors/Bulgarian/ERR_ICAP_FAILURE -diff -N errors/Bulgarian/ERR_ICAP_FAILURE ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ errors/Bulgarian/ERR_ICAP_FAILURE 8 Dec 2003 12:30:56 -0000 1.1.2.1 -@@ -0,0 +1,31 @@ -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -+<HTML><HEAD> -+<TITLE>ERROR: The requested URL could not be retrieved</TITLE> -+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE> -+</HEAD><BODY> -+<H1>ERROR</H1> -+<H2>The requested URL could not be retrieved</H2> -+<HR noshade size="1px"> -+<P> -+While attempting to retrieve the URL: -+<A HREF="%U">%U</A> -+<P> -+the following error was encountered: -+<UL> -+<LI> -+<STRONG> -+ICAP protocol error. -+</STRONG> -+</UL> -+ -+<P> -+<P> -+Some aspect of the ICAP communication failed. Possible problems: -+<UL> -+<LI>ICAP server is not reachable. -+<LI>Illegal response from ICAP server. -+</UL> -+</P> -+ -+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. -+ -Index: errors/Catalan/ERR_ICAP_FAILURE -=================================================================== -RCS file: errors/Catalan/ERR_ICAP_FAILURE -diff -N errors/Catalan/ERR_ICAP_FAILURE ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ errors/Catalan/ERR_ICAP_FAILURE 8 Dec 2003 12:30:57 -0000 1.1.2.1 -@@ -0,0 +1,31 @@ -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -+<HTML><HEAD> -+<TITLE>ERROR: The requested URL could not be retrieved</TITLE> -+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE> -+</HEAD><BODY> -+<H1>ERROR</H1> -+<H2>The requested URL could not be retrieved</H2> -+<HR noshade size="1px"> -+<P> -+While attempting to retrieve the URL: -+<A HREF="%U">%U</A> -+<P> -+the following error was encountered: -+<UL> -+<LI> -+<STRONG> -+ICAP protocol error. -+</STRONG> -+</UL> -+ -+<P> -+<P> -+Some aspect of the ICAP communication failed. Possible problems: -+<UL> -+<LI>ICAP server is not reachable. -+<LI>Illegal response from ICAP server. -+</UL> -+</P> -+ -+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. -+ -Index: errors/Czech/ERR_ICAP_FAILURE -=================================================================== -RCS file: errors/Czech/ERR_ICAP_FAILURE -diff -N errors/Czech/ERR_ICAP_FAILURE ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ errors/Czech/ERR_ICAP_FAILURE 8 Dec 2003 12:30:57 -0000 1.1.2.1 -@@ -0,0 +1,31 @@ -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -+<HTML><HEAD> -+<TITLE>ERROR: The requested URL could not be retrieved</TITLE> -+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE> -+</HEAD><BODY> -+<H1>ERROR</H1> -+<H2>The requested URL could not be retrieved</H2> -+<HR noshade size="1px"> -+<P> -+While attempting to retrieve the URL: -+<A HREF="%U">%U</A> -+<P> -+the following error was encountered: -+<UL> -+<LI> -+<STRONG> -+ICAP protocol error. -+</STRONG> -+</UL> -+ -+<P> -+<P> -+Some aspect of the ICAP communication failed. Possible problems: -+<UL> -+<LI>ICAP server is not reachable. -+<LI>Illegal response from ICAP server. -+</UL> -+</P> -+ -+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. -+ -Index: errors/Danish/ERR_ICAP_FAILURE -=================================================================== -RCS file: errors/Danish/ERR_ICAP_FAILURE -diff -N errors/Danish/ERR_ICAP_FAILURE ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ errors/Danish/ERR_ICAP_FAILURE 8 Dec 2003 12:30:57 -0000 1.1.2.1 -@@ -0,0 +1,31 @@ -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -+<HTML><HEAD> -+<TITLE>ERROR: The requested URL could not be retrieved</TITLE> -+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE> -+</HEAD><BODY> -+<H1>ERROR</H1> -+<H2>The requested URL could not be retrieved</H2> -+<HR noshade size="1px"> -+<P> -+While attempting to retrieve the URL: -+<A HREF="%U">%U</A> -+<P> -+the following error was encountered: -+<UL> -+<LI> -+<STRONG> -+ICAP protocol error. -+</STRONG> -+</UL> -+ -+<P> -+<P> -+Some aspect of the ICAP communication failed. Possible problems: -+<UL> -+<LI>ICAP server is not reachable. -+<LI>Illegal response from ICAP server. -+</UL> -+</P> -+ -+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. -+ -Index: errors/Dutch/ERR_ICAP_FAILURE -=================================================================== -RCS file: errors/Dutch/ERR_ICAP_FAILURE -diff -N errors/Dutch/ERR_ICAP_FAILURE ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ errors/Dutch/ERR_ICAP_FAILURE 8 Dec 2003 12:30:57 -0000 1.1.2.1 -@@ -0,0 +1,31 @@ -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -+<HTML><HEAD> -+<TITLE>ERROR: The requested URL could not be retrieved</TITLE> -+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE> -+</HEAD><BODY> -+<H1>ERROR</H1> -+<H2>The requested URL could not be retrieved</H2> -+<HR noshade size="1px"> -+<P> -+While attempting to retrieve the URL: -+<A HREF="%U">%U</A> -+<P> -+the following error was encountered: -+<UL> -+<LI> -+<STRONG> -+ICAP protocol error. -+</STRONG> -+</UL> -+ -+<P> -+<P> -+Some aspect of the ICAP communication failed. Possible problems: -+<UL> -+<LI>ICAP server is not reachable. -+<LI>Illegal response from ICAP server. -+</UL> -+</P> -+ -+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. -+ -Index: errors/English/ERR_ICAP_FAILURE -=================================================================== -RCS file: errors/English/ERR_ICAP_FAILURE -diff -N errors/English/ERR_ICAP_FAILURE ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ errors/English/ERR_ICAP_FAILURE 8 Dec 2003 12:30:57 -0000 1.1.2.2 -@@ -0,0 +1,31 @@ -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -+<HTML><HEAD> -+<TITLE>ERROR: The requested URL could not be retrieved</TITLE> -+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE> -+</HEAD><BODY> -+<H1>ERROR</H1> -+<H2>The requested URL could not be retrieved</H2> -+<HR noshade size="1px"> -+<P> -+While attempting to retrieve the URL: -+<A HREF="%U">%U</A> -+<P> -+the following error was encountered: -+<UL> -+<LI> -+<STRONG> -+ICAP protocol error. -+</STRONG> -+</UL> -+ -+<P> -+<P> -+Some aspect of the ICAP communication failed. Possible problems: -+<UL> -+<LI>ICAP server is not reachable. -+<LI>Illegal response from ICAP server. -+</UL> -+</P> -+ -+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. -+ -Index: errors/Estonian/ERR_ICAP_FAILURE -=================================================================== -RCS file: errors/Estonian/ERR_ICAP_FAILURE -diff -N errors/Estonian/ERR_ICAP_FAILURE ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ errors/Estonian/ERR_ICAP_FAILURE 8 Dec 2003 12:30:58 -0000 1.1.2.1 -@@ -0,0 +1,31 @@ -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -+<HTML><HEAD> -+<TITLE>ERROR: The requested URL could not be retrieved</TITLE> -+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE> -+</HEAD><BODY> -+<H1>ERROR</H1> -+<H2>The requested URL could not be retrieved</H2> -+<HR noshade size="1px"> -+<P> -+While attempting to retrieve the URL: -+<A HREF="%U">%U</A> -+<P> -+the following error was encountered: -+<UL> -+<LI> -+<STRONG> -+ICAP protocol error. -+</STRONG> -+</UL> -+ -+<P> -+<P> -+Some aspect of the ICAP communication failed. Possible problems: -+<UL> -+<LI>ICAP server is not reachable. -+<LI>Illegal response from ICAP server. -+</UL> -+</P> -+ -+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. -+ -Index: errors/Finnish/ERR_ICAP_FAILURE -=================================================================== -RCS file: errors/Finnish/ERR_ICAP_FAILURE -diff -N errors/Finnish/ERR_ICAP_FAILURE ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ errors/Finnish/ERR_ICAP_FAILURE 8 Dec 2003 12:30:58 -0000 1.1.2.1 -@@ -0,0 +1,31 @@ -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -+<HTML><HEAD> -+<TITLE>ERROR: The requested URL could not be retrieved</TITLE> -+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE> -+</HEAD><BODY> -+<H1>ERROR</H1> -+<H2>The requested URL could not be retrieved</H2> -+<HR noshade size="1px"> -+<P> -+While attempting to retrieve the URL: -+<A HREF="%U">%U</A> -+<P> -+the following error was encountered: -+<UL> -+<LI> -+<STRONG> -+ICAP protocol error. -+</STRONG> -+</UL> -+ -+<P> -+<P> -+Some aspect of the ICAP communication failed. Possible problems: -+<UL> -+<LI>ICAP server is not reachable. -+<LI>Illegal response from ICAP server. -+</UL> -+</P> -+ -+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. -+ -Index: errors/French/ERR_ICAP_FAILURE -=================================================================== -RCS file: errors/French/ERR_ICAP_FAILURE -diff -N errors/French/ERR_ICAP_FAILURE ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ errors/French/ERR_ICAP_FAILURE 8 Dec 2003 12:30:58 -0000 1.1.2.1 -@@ -0,0 +1,31 @@ -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -+<HTML><HEAD> -+<TITLE>ERROR: The requested URL could not be retrieved</TITLE> -+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE> -+</HEAD><BODY> -+<H1>ERROR</H1> -+<H2>The requested URL could not be retrieved</H2> -+<HR noshade size="1px"> -+<P> -+While attempting to retrieve the URL: -+<A HREF="%U">%U</A> -+<P> -+the following error was encountered: -+<UL> -+<LI> -+<STRONG> -+ICAP protocol error. -+</STRONG> -+</UL> -+ -+<P> -+<P> -+Some aspect of the ICAP communication failed. Possible problems: -+<UL> -+<LI>ICAP server is not reachable. -+<LI>Illegal response from ICAP server. -+</UL> -+</P> -+ -+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. -+ -Index: errors/German/ERR_ICAP_FAILURE -=================================================================== -RCS file: errors/German/ERR_ICAP_FAILURE -diff -N errors/German/ERR_ICAP_FAILURE ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ errors/German/ERR_ICAP_FAILURE 23 Mar 2004 08:20:05 -0000 1.1.2.2 -@@ -0,0 +1,33 @@ -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -+<HTML><HEAD> -+<TITLE>FEHLER: Der angeforderte URL konnte nicht geholt werden</TITLE> -+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE> -+</HEAD><BODY> -+<H1>FEHLER</H1> -+<H2>Der angeforderte URL konnte nicht geholt werden</H2> -+<HR noshade size="1px"> -+<P> -+Während des Versuches, den URL<BR> -+<A HREF="%U">%U</A> -+ -+<BR> -+zu laden, trat der folgende Fehler auf: -+<UL> -+<LI> -+<STRONG> -+ICAP-Protokollfehler -+</STRONG> -+</UL> -+ -+<P> -+<P> -+Es trat ein Problem bei der ICAP-Kommunikation auf. Mögliche Gründe: -+<UL> -+<LI>Nicht erreichbarer ICAP-Server -+<LI>Ungültige Antwort vom ICAP-Server -+ -+</UL> -+</P> -+ -+<P>Ihr Cache Administrator ist <A HREF="mailto:%w">%w</A>. -+ -Index: errors/Greek/ERR_ICAP_FAILURE -=================================================================== -RCS file: errors/Greek/ERR_ICAP_FAILURE -diff -N errors/Greek/ERR_ICAP_FAILURE ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ errors/Greek/ERR_ICAP_FAILURE 24 Sep 2005 10:31:00 -0000 1.1.2.1 -@@ -0,0 +1,31 @@ -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -+<HTML><HEAD> -+<TITLE>ERROR: The requested URL could not be retrieved</TITLE> -+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE> -+</HEAD><BODY> -+<H1>ERROR</H1> -+<H2>The requested URL could not be retrieved</H2> -+<HR noshade size="1px"> -+<P> -+While attempting to retrieve the URL: -+<A HREF="%U">%U</A> -+<P> -+the following error was encountered: -+<UL> -+<LI> -+<STRONG> -+ICAP protocol error. -+</STRONG> -+</UL> -+ -+<P> -+<P> -+Some aspect of the ICAP communication failed. Possible problems: -+<UL> -+<LI>ICAP server is not reachable. -+<LI>Illegal response from ICAP server. -+</UL> -+</P> -+ -+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. -+ -Index: errors/Hebrew/ERR_ICAP_FAILURE -=================================================================== -RCS file: errors/Hebrew/ERR_ICAP_FAILURE -diff -N errors/Hebrew/ERR_ICAP_FAILURE ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ errors/Hebrew/ERR_ICAP_FAILURE 8 Dec 2003 12:30:59 -0000 1.1.2.1 -@@ -0,0 +1,31 @@ -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -+<HTML><HEAD> -+<TITLE>ERROR: The requested URL could not be retrieved</TITLE> -+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE> -+</HEAD><BODY> -+<H1>ERROR</H1> -+<H2>The requested URL could not be retrieved</H2> -+<HR noshade size="1px"> -+<P> -+While attempting to retrieve the URL: -+<A HREF="%U">%U</A> -+<P> -+the following error was encountered: -+<UL> -+<LI> -+<STRONG> -+ICAP protocol error. -+</STRONG> -+</UL> -+ -+<P> -+<P> -+Some aspect of the ICAP communication failed. Possible problems: -+<UL> -+<LI>ICAP server is not reachable. -+<LI>Illegal response from ICAP server. -+</UL> -+</P> -+ -+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. -+ -Index: errors/Hungarian/ERR_ICAP_FAILURE -=================================================================== -RCS file: errors/Hungarian/ERR_ICAP_FAILURE -diff -N errors/Hungarian/ERR_ICAP_FAILURE ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ errors/Hungarian/ERR_ICAP_FAILURE 8 Dec 2003 12:30:59 -0000 1.1.2.1 -@@ -0,0 +1,31 @@ -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -+<HTML><HEAD> -+<TITLE>ERROR: The requested URL could not be retrieved</TITLE> -+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE> -+</HEAD><BODY> -+<H1>ERROR</H1> -+<H2>The requested URL could not be retrieved</H2> -+<HR noshade size="1px"> -+<P> -+While attempting to retrieve the URL: -+<A HREF="%U">%U</A> -+<P> -+the following error was encountered: -+<UL> -+<LI> -+<STRONG> -+ICAP protocol error. -+</STRONG> -+</UL> -+ -+<P> -+<P> -+Some aspect of the ICAP communication failed. Possible problems: -+<UL> -+<LI>ICAP server is not reachable. -+<LI>Illegal response from ICAP server. -+</UL> -+</P> -+ -+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. -+ -Index: errors/Italian/ERR_ICAP_FAILURE -=================================================================== -RCS file: errors/Italian/ERR_ICAP_FAILURE -diff -N errors/Italian/ERR_ICAP_FAILURE ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ errors/Italian/ERR_ICAP_FAILURE 8 Dec 2003 12:31:00 -0000 1.1.2.1 -@@ -0,0 +1,31 @@ -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -+<HTML><HEAD> -+<TITLE>ERROR: The requested URL could not be retrieved</TITLE> -+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE> -+</HEAD><BODY> -+<H1>ERROR</H1> -+<H2>The requested URL could not be retrieved</H2> -+<HR noshade size="1px"> -+<P> -+While attempting to retrieve the URL: -+<A HREF="%U">%U</A> -+<P> -+the following error was encountered: -+<UL> -+<LI> -+<STRONG> -+ICAP protocol error. -+</STRONG> -+</UL> -+ -+<P> -+<P> -+Some aspect of the ICAP communication failed. Possible problems: -+<UL> -+<LI>ICAP server is not reachable. -+<LI>Illegal response from ICAP server. -+</UL> -+</P> -+ -+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. -+ -Index: errors/Japanese/ERR_ICAP_FAILURE -=================================================================== -RCS file: errors/Japanese/ERR_ICAP_FAILURE -diff -N errors/Japanese/ERR_ICAP_FAILURE ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ errors/Japanese/ERR_ICAP_FAILURE 8 Dec 2003 12:31:00 -0000 1.1.2.1 -@@ -0,0 +1,31 @@ -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -+<HTML><HEAD> -+<TITLE>ERROR: The requested URL could not be retrieved</TITLE> -+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE> -+</HEAD><BODY> -+<H1>ERROR</H1> -+<H2>The requested URL could not be retrieved</H2> -+<HR noshade size="1px"> -+<P> -+While attempting to retrieve the URL: -+<A HREF="%U">%U</A> -+<P> -+the following error was encountered: -+<UL> -+<LI> -+<STRONG> -+ICAP protocol error. -+</STRONG> -+</UL> -+ -+<P> -+<P> -+Some aspect of the ICAP communication failed. Possible problems: -+<UL> -+<LI>ICAP server is not reachable. -+<LI>Illegal response from ICAP server. -+</UL> -+</P> -+ -+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. -+ -Index: errors/Korean/ERR_ICAP_FAILURE -=================================================================== -RCS file: errors/Korean/ERR_ICAP_FAILURE -diff -N errors/Korean/ERR_ICAP_FAILURE ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ errors/Korean/ERR_ICAP_FAILURE 8 Dec 2003 12:31:00 -0000 1.1.2.1 -@@ -0,0 +1,31 @@ -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -+<HTML><HEAD> -+<TITLE>ERROR: The requested URL could not be retrieved</TITLE> -+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE> -+</HEAD><BODY> -+<H1>ERROR</H1> -+<H2>The requested URL could not be retrieved</H2> -+<HR noshade size="1px"> -+<P> -+While attempting to retrieve the URL: -+<A HREF="%U">%U</A> -+<P> -+the following error was encountered: -+<UL> -+<LI> -+<STRONG> -+ICAP protocol error. -+</STRONG> -+</UL> -+ -+<P> -+<P> -+Some aspect of the ICAP communication failed. Possible problems: -+<UL> -+<LI>ICAP server is not reachable. -+<LI>Illegal response from ICAP server. -+</UL> -+</P> -+ -+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. -+ -Index: errors/Lithuanian/ERR_ICAP_FAILURE -=================================================================== -RCS file: errors/Lithuanian/ERR_ICAP_FAILURE -diff -N errors/Lithuanian/ERR_ICAP_FAILURE ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ errors/Lithuanian/ERR_ICAP_FAILURE 8 Dec 2003 12:31:00 -0000 1.1.2.1 -@@ -0,0 +1,31 @@ -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -+<HTML><HEAD> -+<TITLE>ERROR: The requested URL could not be retrieved</TITLE> -+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE> -+</HEAD><BODY> -+<H1>ERROR</H1> -+<H2>The requested URL could not be retrieved</H2> -+<HR noshade size="1px"> -+<P> -+While attempting to retrieve the URL: -+<A HREF="%U">%U</A> -+<P> -+the following error was encountered: -+<UL> -+<LI> -+<STRONG> -+ICAP protocol error. -+</STRONG> -+</UL> -+ -+<P> -+<P> -+Some aspect of the ICAP communication failed. Possible problems: -+<UL> -+<LI>ICAP server is not reachable. -+<LI>Illegal response from ICAP server. -+</UL> -+</P> -+ -+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. -+ -Index: errors/Polish/ERR_ICAP_FAILURE -=================================================================== -RCS file: errors/Polish/ERR_ICAP_FAILURE -diff -N errors/Polish/ERR_ICAP_FAILURE ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ errors/Polish/ERR_ICAP_FAILURE 8 Dec 2003 12:31:00 -0000 1.1.2.1 -@@ -0,0 +1,31 @@ -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -+<HTML><HEAD> -+<TITLE>ERROR: The requested URL could not be retrieved</TITLE> -+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE> -+</HEAD><BODY> -+<H1>ERROR</H1> -+<H2>The requested URL could not be retrieved</H2> -+<HR noshade size="1px"> -+<P> -+While attempting to retrieve the URL: -+<A HREF="%U">%U</A> -+<P> -+the following error was encountered: -+<UL> -+<LI> -+<STRONG> -+ICAP protocol error. -+</STRONG> -+</UL> -+ -+<P> -+<P> -+Some aspect of the ICAP communication failed. Possible problems: -+<UL> -+<LI>ICAP server is not reachable. -+<LI>Illegal response from ICAP server. -+</UL> -+</P> -+ -+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. -+ -Index: errors/Portuguese/ERR_ICAP_FAILURE -=================================================================== -RCS file: errors/Portuguese/ERR_ICAP_FAILURE -diff -N errors/Portuguese/ERR_ICAP_FAILURE ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ errors/Portuguese/ERR_ICAP_FAILURE 8 Dec 2003 12:31:01 -0000 1.1.2.1 -@@ -0,0 +1,31 @@ -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -+<HTML><HEAD> -+<TITLE>ERROR: The requested URL could not be retrieved</TITLE> -+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE> -+</HEAD><BODY> -+<H1>ERROR</H1> -+<H2>The requested URL could not be retrieved</H2> -+<HR noshade size="1px"> -+<P> -+While attempting to retrieve the URL: -+<A HREF="%U">%U</A> -+<P> -+the following error was encountered: -+<UL> -+<LI> -+<STRONG> -+ICAP protocol error. -+</STRONG> -+</UL> -+ -+<P> -+<P> -+Some aspect of the ICAP communication failed. Possible problems: -+<UL> -+<LI>ICAP server is not reachable. -+<LI>Illegal response from ICAP server. -+</UL> -+</P> -+ -+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. -+ -Index: errors/Romanian/ERR_ICAP_FAILURE -=================================================================== -RCS file: errors/Romanian/ERR_ICAP_FAILURE -diff -N errors/Romanian/ERR_ICAP_FAILURE ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ errors/Romanian/ERR_ICAP_FAILURE 8 Dec 2003 12:31:01 -0000 1.1.2.1 -@@ -0,0 +1,31 @@ -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -+<HTML><HEAD> -+<TITLE>ERROR: The requested URL could not be retrieved</TITLE> -+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE> -+</HEAD><BODY> -+<H1>ERROR</H1> -+<H2>The requested URL could not be retrieved</H2> -+<HR noshade size="1px"> -+<P> -+While attempting to retrieve the URL: -+<A HREF="%U">%U</A> -+<P> -+the following error was encountered: -+<UL> -+<LI> -+<STRONG> -+ICAP protocol error. -+</STRONG> -+</UL> -+ -+<P> -+<P> -+Some aspect of the ICAP communication failed. Possible problems: -+<UL> -+<LI>ICAP server is not reachable. -+<LI>Illegal response from ICAP server. -+</UL> -+</P> -+ -+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. -+ -Index: errors/Russian-1251/ERR_ICAP_FAILURE -=================================================================== -RCS file: errors/Russian-1251/ERR_ICAP_FAILURE -diff -N errors/Russian-1251/ERR_ICAP_FAILURE ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ errors/Russian-1251/ERR_ICAP_FAILURE 8 Dec 2003 12:31:02 -0000 1.1.2.1 -@@ -0,0 +1,31 @@ -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -+<HTML><HEAD> -+<TITLE>ERROR: The requested URL could not be retrieved</TITLE> -+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE> -+</HEAD><BODY> -+<H1>ERROR</H1> -+<H2>The requested URL could not be retrieved</H2> -+<HR noshade size="1px"> -+<P> -+While attempting to retrieve the URL: -+<A HREF="%U">%U</A> -+<P> -+the following error was encountered: -+<UL> -+<LI> -+<STRONG> -+ICAP protocol error. -+</STRONG> -+</UL> -+ -+<P> -+<P> -+Some aspect of the ICAP communication failed. Possible problems: -+<UL> -+<LI>ICAP server is not reachable. -+<LI>Illegal response from ICAP server. -+</UL> -+</P> -+ -+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. -+ -Index: errors/Russian-koi8-r/ERR_ICAP_FAILURE -=================================================================== -RCS file: errors/Russian-koi8-r/ERR_ICAP_FAILURE -diff -N errors/Russian-koi8-r/ERR_ICAP_FAILURE ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ errors/Russian-koi8-r/ERR_ICAP_FAILURE 8 Dec 2003 12:31:02 -0000 1.1.2.1 -@@ -0,0 +1,31 @@ -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -+<HTML><HEAD> -+<TITLE>ERROR: The requested URL could not be retrieved</TITLE> -+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE> -+</HEAD><BODY> -+<H1>ERROR</H1> -+<H2>The requested URL could not be retrieved</H2> -+<HR noshade size="1px"> -+<P> -+While attempting to retrieve the URL: -+<A HREF="%U">%U</A> -+<P> -+the following error was encountered: -+<UL> -+<LI> -+<STRONG> -+ICAP protocol error. -+</STRONG> -+</UL> -+ -+<P> -+<P> -+Some aspect of the ICAP communication failed. Possible problems: -+<UL> -+<LI>ICAP server is not reachable. -+<LI>Illegal response from ICAP server. -+</UL> -+</P> -+ -+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. -+ -Index: errors/Serbian/ERR_ICAP_FAILURE -=================================================================== -RCS file: errors/Serbian/ERR_ICAP_FAILURE -diff -N errors/Serbian/ERR_ICAP_FAILURE ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ errors/Serbian/ERR_ICAP_FAILURE 8 Dec 2003 12:31:02 -0000 1.1.2.1 -@@ -0,0 +1,31 @@ -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -+<HTML><HEAD> -+<TITLE>ERROR: The requested URL could not be retrieved</TITLE> -+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE> -+</HEAD><BODY> -+<H1>ERROR</H1> -+<H2>The requested URL could not be retrieved</H2> -+<HR noshade size="1px"> -+<P> -+While attempting to retrieve the URL: -+<A HREF="%U">%U</A> -+<P> -+the following error was encountered: -+<UL> -+<LI> -+<STRONG> -+ICAP protocol error. -+</STRONG> -+</UL> -+ -+<P> -+<P> -+Some aspect of the ICAP communication failed. Possible problems: -+<UL> -+<LI>ICAP server is not reachable. -+<LI>Illegal response from ICAP server. -+</UL> -+</P> -+ -+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. -+ -Index: errors/Simplify_Chinese/ERR_ICAP_FAILURE -=================================================================== -RCS file: errors/Simplify_Chinese/ERR_ICAP_FAILURE -diff -N errors/Simplify_Chinese/ERR_ICAP_FAILURE ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ errors/Simplify_Chinese/ERR_ICAP_FAILURE 8 Dec 2003 12:31:02 -0000 1.1.2.1 -@@ -0,0 +1,31 @@ -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -+<HTML><HEAD> -+<TITLE>ERROR: The requested URL could not be retrieved</TITLE> -+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE> -+</HEAD><BODY> -+<H1>ERROR</H1> -+<H2>The requested URL could not be retrieved</H2> -+<HR noshade size="1px"> -+<P> -+While attempting to retrieve the URL: -+<A HREF="%U">%U</A> -+<P> -+the following error was encountered: -+<UL> -+<LI> -+<STRONG> -+ICAP protocol error. -+</STRONG> -+</UL> -+ -+<P> -+<P> -+Some aspect of the ICAP communication failed. Possible problems: -+<UL> -+<LI>ICAP server is not reachable. -+<LI>Illegal response from ICAP server. -+</UL> -+</P> -+ -+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. -+ -Index: errors/Slovak/ERR_ICAP_FAILURE -=================================================================== -RCS file: errors/Slovak/ERR_ICAP_FAILURE -diff -N errors/Slovak/ERR_ICAP_FAILURE ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ errors/Slovak/ERR_ICAP_FAILURE 8 Dec 2003 12:31:03 -0000 1.1.2.1 -@@ -0,0 +1,31 @@ -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -+<HTML><HEAD> -+<TITLE>ERROR: The requested URL could not be retrieved</TITLE> -+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE> -+</HEAD><BODY> -+<H1>ERROR</H1> -+<H2>The requested URL could not be retrieved</H2> -+<HR noshade size="1px"> -+<P> -+While attempting to retrieve the URL: -+<A HREF="%U">%U</A> -+<P> -+the following error was encountered: -+<UL> -+<LI> -+<STRONG> -+ICAP protocol error. -+</STRONG> -+</UL> -+ -+<P> -+<P> -+Some aspect of the ICAP communication failed. Possible problems: -+<UL> -+<LI>ICAP server is not reachable. -+<LI>Illegal response from ICAP server. -+</UL> -+</P> -+ -+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. -+ -Index: errors/Spanish/ERR_ICAP_FAILURE -=================================================================== -RCS file: errors/Spanish/ERR_ICAP_FAILURE -diff -N errors/Spanish/ERR_ICAP_FAILURE ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ errors/Spanish/ERR_ICAP_FAILURE 8 Dec 2003 12:31:03 -0000 1.1.2.1 -@@ -0,0 +1,31 @@ -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -+<HTML><HEAD> -+<TITLE>ERROR: The requested URL could not be retrieved</TITLE> -+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE> -+</HEAD><BODY> -+<H1>ERROR</H1> -+<H2>The requested URL could not be retrieved</H2> -+<HR noshade size="1px"> -+<P> -+While attempting to retrieve the URL: -+<A HREF="%U">%U</A> -+<P> -+the following error was encountered: -+<UL> -+<LI> -+<STRONG> -+ICAP protocol error. -+</STRONG> -+</UL> -+ -+<P> -+<P> -+Some aspect of the ICAP communication failed. Possible problems: -+<UL> -+<LI>ICAP server is not reachable. -+<LI>Illegal response from ICAP server. -+</UL> -+</P> -+ -+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. -+ -Index: errors/Swedish/ERR_ICAP_FAILURE -=================================================================== -RCS file: errors/Swedish/ERR_ICAP_FAILURE -diff -N errors/Swedish/ERR_ICAP_FAILURE ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ errors/Swedish/ERR_ICAP_FAILURE 8 Dec 2003 12:31:03 -0000 1.1.2.1 -@@ -0,0 +1,31 @@ -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -+<HTML><HEAD> -+<TITLE>ERROR: The requested URL could not be retrieved</TITLE> -+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE> -+</HEAD><BODY> -+<H1>ERROR</H1> -+<H2>The requested URL could not be retrieved</H2> -+<HR noshade size="1px"> -+<P> -+While attempting to retrieve the URL: -+<A HREF="%U">%U</A> -+<P> -+the following error was encountered: -+<UL> -+<LI> -+<STRONG> -+ICAP protocol error. -+</STRONG> -+</UL> -+ -+<P> -+<P> -+Some aspect of the ICAP communication failed. Possible problems: -+<UL> -+<LI>ICAP server is not reachable. -+<LI>Illegal response from ICAP server. -+</UL> -+</P> -+ -+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. -+ -Index: errors/Traditional_Chinese/ERR_ICAP_FAILURE -=================================================================== -RCS file: errors/Traditional_Chinese/ERR_ICAP_FAILURE -diff -N errors/Traditional_Chinese/ERR_ICAP_FAILURE ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ errors/Traditional_Chinese/ERR_ICAP_FAILURE 8 Dec 2003 12:31:03 -0000 1.1.2.1 -@@ -0,0 +1,31 @@ -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -+<HTML><HEAD> -+<TITLE>ERROR: The requested URL could not be retrieved</TITLE> -+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE> -+</HEAD><BODY> -+<H1>ERROR</H1> -+<H2>The requested URL could not be retrieved</H2> -+<HR noshade size="1px"> -+<P> -+While attempting to retrieve the URL: -+<A HREF="%U">%U</A> -+<P> -+the following error was encountered: -+<UL> -+<LI> -+<STRONG> -+ICAP protocol error. -+</STRONG> -+</UL> -+ -+<P> -+<P> -+Some aspect of the ICAP communication failed. Possible problems: -+<UL> -+<LI>ICAP server is not reachable. -+<LI>Illegal response from ICAP server. -+</UL> -+</P> -+ -+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. -+ -Index: errors/Turkish/ERR_ICAP_FAILURE -=================================================================== -RCS file: errors/Turkish/ERR_ICAP_FAILURE -diff -N errors/Turkish/ERR_ICAP_FAILURE ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ errors/Turkish/ERR_ICAP_FAILURE 8 Dec 2003 12:31:04 -0000 1.1.2.1 -@@ -0,0 +1,31 @@ -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -+<HTML><HEAD> -+<TITLE>ERROR: The requested URL could not be retrieved</TITLE> -+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE> -+</HEAD><BODY> -+<H1>ERROR</H1> -+<H2>The requested URL could not be retrieved</H2> -+<HR noshade size="1px"> -+<P> -+While attempting to retrieve the URL: -+<A HREF="%U">%U</A> -+<P> -+the following error was encountered: -+<UL> -+<LI> -+<STRONG> -+ICAP protocol error. -+</STRONG> -+</UL> -+ -+<P> -+<P> -+Some aspect of the ICAP communication failed. Possible problems: -+<UL> -+<LI>ICAP server is not reachable. -+<LI>Illegal response from ICAP server. -+</UL> -+</P> -+ -+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. -+ -Index: include/util.h -=================================================================== -RCS file: /cvsroot/squid/squid/include/util.h,v -retrieving revision 1.10 -retrieving revision 1.10.30.2 -diff -p -u -b -r1.10 -r1.10.30.2 ---- include/util.h 17 Oct 2001 12:30:51 -0000 1.10 -+++ include/util.h 6 Apr 2004 13:04:37 -0000 1.10.30.2 -@@ -132,4 +132,12 @@ double drand48(void); - */ - int statMemoryAccounted(void); - -+#ifndef HAVE_STRNSTR -+extern char *strnstr(const char *haystack, const char *needle, size_t haystacklen); -+#endif -+ -+#ifndef HAVE_STRCASESTR -+extern char *strcasestr(const char *haystack, const char *needle); -+#endif -+ - #endif /* SQUID_UTIL_H */ -Index: lib/strcasestr.c -=================================================================== -RCS file: lib/strcasestr.c -diff -N lib/strcasestr.c ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ lib/strcasestr.c 6 Apr 2004 13:04:38 -0000 1.1.2.1 -@@ -0,0 +1,126 @@ -+/* Return the offset of one string within another. -+ Copyright (C) 1994,1996,1997,1998,1999,2000 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, write to the Free -+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -+ 02111-1307 USA. */ -+ -+/* -+ * My personal strstr() implementation that beats most other algorithms. -+ * Until someone tells me otherwise, I assume that this is the -+ * fastest implementation of strstr() in C. -+ * I deliberately chose not to comment it. You should have at least -+ * as much fun trying to understand it, as I had to write it :-). -+ * -+ * Stephen R. van den Berg, berg@pool.informatik.rwth-aachen.de */ -+ -+/* -+ * modified to work outside of glibc (rhorstmann, 06/04/2004) -+ */ -+ -+#include "config.h" -+#ifndef HAVE_STRCASESTR -+#include <ctype.h> -+ -+typedef unsigned chartype; -+ -+char * -+strcasestr (phaystack, pneedle) -+ const char *phaystack; -+ const char *pneedle; -+{ -+ register const unsigned char *haystack, *needle; -+ register chartype b, c; -+ -+ haystack = (const unsigned char *) phaystack; -+ needle = (const unsigned char *) pneedle; -+ -+ b = tolower (*needle); -+ if (b != '\0') -+ { -+ haystack--; /* possible ANSI violation */ -+ do -+ { -+ c = *++haystack; -+ if (c == '\0') -+ goto ret0; -+ } -+ while (tolower (c) != (int) b); -+ -+ c = tolower (*++needle); -+ if (c == '\0') -+ goto foundneedle; -+ ++needle; -+ goto jin; -+ -+ for (;;) -+ { -+ register chartype a; -+ register const unsigned char *rhaystack, *rneedle; -+ -+ do -+ { -+ a = *++haystack; -+ if (a == '\0') -+ goto ret0; -+ if (tolower (a) == (int) b) -+ break; -+ a = *++haystack; -+ if (a == '\0') -+ goto ret0; -+shloop: -+ ; -+ } -+ while (tolower (a) != (int) b); -+ -+jin: a = *++haystack; -+ if (a == '\0') -+ goto ret0; -+ -+ if (tolower (a) != (int) c) -+ goto shloop; -+ -+ rhaystack = haystack-- + 1; -+ rneedle = needle; -+ a = tolower (*rneedle); -+ -+ if (tolower (*rhaystack) == (int) a) -+ do -+ { -+ if (a == '\0') -+ goto foundneedle; -+ ++rhaystack; -+ a = tolower (*++needle); -+ if (tolower (*rhaystack) != (int) a) -+ break; -+ if (a == '\0') -+ goto foundneedle; -+ ++rhaystack; -+ a = tolower (*++needle); -+ } -+ while (tolower (*rhaystack) == (int) a); -+ -+ needle = rneedle; /* took the register-poor approach */ -+ -+ if (a == '\0') -+ break; -+ } -+ } -+foundneedle: -+ return (char*) haystack; -+ret0: -+ return 0; -+} -+#endif -Index: lib/strnstr.c -=================================================================== -RCS file: lib/strnstr.c -diff -N lib/strnstr.c ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ lib/strnstr.c 16 May 2005 20:52:40 -0000 1.1.2.2 -@@ -0,0 +1,52 @@ -+/* -+ * Copyright (C) 2003 Nikos Mavroyanopoulos -+ * -+ * This file is part of GNUTLS. -+ * -+ * The GNUTLS library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ */ -+ -+ /* -+ * DW 2003/10/17: -+ * Changed 'ssize_t' types to 'size_t' -+ */ -+ -+#include "config.h" -+#ifndef HAVE_STRNSTR -+#include <string.h> -+#include <util.h> -+ -+char *strnstr(const char *haystack, const char *needle, size_t haystacklen) -+{ -+ char *p; -+ size_t plen; -+ size_t len = strlen(needle); -+ -+ if (*needle == '\0') /* everything matches empty string */ -+ return (char*) haystack; -+ -+ plen = haystacklen; -+ for (p = (char*) haystack; p != NULL; p = memchr(p + 1, *needle, plen-1)) { -+ plen = haystacklen - (p - haystack); -+ -+ if (plen < len) return NULL; -+ -+ if (strncmp(p, needle, len) == 0) -+ return (p); -+ } -+ return NULL; -+} -+#endif -Index: src/MemBuf.c -=================================================================== -RCS file: /cvsroot/squid/squid/src/MemBuf.c,v -retrieving revision 1.5.30.3 -retrieving revision 1.5.44.8 -diff -p -u -b -r1.5.30.3 -r1.5.44.8 ---- src/MemBuf.c 26 Mar 2005 03:15:54 -0000 1.5.30.3 -+++ src/MemBuf.c 28 Mar 2005 18:02:04 -0000 1.5.44.8 -@@ -386,3 +386,15 @@ memBufReport(MemBuf * mb) - assert(mb); - memBufPrintf(mb, "memBufReport is not yet implemented @?@\n"); - } -+ -+int -+memBufRead(int fd, MemBuf * mb) -+{ -+ int len; -+ if (mb->capacity == mb->size) -+ memBufGrow(mb, SQUID_TCP_SO_RCVBUF); -+ len = FD_READ_METHOD(fd, mb->buf + mb->size, mb->capacity - mb->size); -+ if (len) -+ mb->size += len; -+ return len; -+} -Index: src/cache_cf.c -=================================================================== -RCS file: /cvsroot/squid/squid/src/cache_cf.c,v -retrieving revision 1.38.6.29 -retrieving revision 1.38.6.11.2.22 -diff -p -u -b -r1.38.6.29 -r1.38.6.11.2.22 ---- src/cache_cf.c 27 Oct 2005 02:13:24 -0000 1.38.6.29 -+++ src/cache_cf.c 23 Nov 2005 20:38:56 -0000 1.38.6.11.2.22 -@@ -2198,6 +2198,587 @@ check_null_body_size_t(dlink_list bodyli - return bodylist.head == NULL; - } - -+#ifdef HS_FEAT_ICAP -+ -+/*************************************************** -+ * prototypes -+ */ -+static int icap_service_process(icap_service * s); -+static void icap_service_init(icap_service * s); -+static void icap_service_destroy(icap_service * s); -+icap_service *icap_service_lookup(char *name); -+static int icap_class_process(icap_class * c); -+static void icap_class_destroy(icap_class * c); -+static void icap_access_destroy(icap_access * a); -+static void dump_wordlist(StoreEntry * entry, const char *name, wordlist * list); -+static void icap_class_add(icap_class * c); -+ -+/*************************************************** -+ * icap_service -+ */ -+ -+/* -+ * example: -+ * icap_service reqmode_precache 0 icap://192.168.0.1:1344/respmod -+ */ -+ -+static void -+parse_icap_service_type(IcapConfig * cfg) -+{ -+ char *token; -+ icap_service *A = NULL; -+ icap_service *B = NULL; -+ icap_service **T = NULL; -+ -+ A = cbdataAlloc(icap_service); -+ icap_service_init(A); -+ parse_string(&A->name); -+ parse_string(&A->type_name); -+ parse_ushort(&A->bypass); -+ parse_string(&A->uri); -+ while ((token = strtok(NULL, w_space))) { -+ if (strcasecmp(token, "no-keep-alive") == 0) { -+ A->keep_alive = 0; -+ } else { -+ debug(3, 0) ("parse_peer: token='%s'\n", token); -+ self_destruct(); -+ } -+ } -+ debug(3, 5) ("parse_icap_service_type (line %d): %s %s %d %s\n", config_lineno, A->name, A->type_name, A->bypass, A->name); -+ if (icap_service_process(A)) { -+ /* put into linked list */ -+ for (B = cfg->service_head, T = &cfg->service_head; B; T = &B->next, B = B->next); -+ *T = A; -+ } else { -+ /* clean up structure */ -+ debug(3, 0) ("parse_icap_service_type (line %d): skipping %s\n", config_lineno, A->name); -+ icap_service_destroy(A); -+ cbdataFree(A); -+ } -+ -+} -+ -+static void -+dump_icap_service_type(StoreEntry * e, const char *name, IcapConfig cfg) -+{ -+ icap_service *current_node = NULL; -+ -+ if (!cfg.service_head) { -+ storeAppendPrintf(e, "%s 0\n", name); -+ return; -+ } -+ current_node = cfg.service_head; -+ -+ while (current_node) { -+ storeAppendPrintf(e, "%s %s %s %d %s", name, current_node->name, current_node->type_name, current_node->bypass, current_node->uri); -+ if (current_node->keep_alive == 0) { -+ storeAppendPrintf(e, " no-keep-alive"); -+ } -+ storeAppendPrintf(e, "\n"); -+ current_node = current_node->next; -+ } -+ -+} -+ -+static void -+free_icap_service_type(IcapConfig * cfg) -+{ -+ while (cfg->service_head) { -+ icap_service *current_node = cfg->service_head; -+ cfg->service_head = current_node->next; -+ icap_service_destroy(current_node); -+ cbdataFree(current_node); -+ } -+} -+ -+/* -+ * parse the raw string and cache some parts that are needed later -+ * returns 1 if everything was ok -+ */ -+static int -+icap_service_process(icap_service * s) -+{ -+ char *start, *end, *tempEnd; -+ char *tailp; -+ unsigned int len; -+ int port_in_uri, resource_in_uri = 0; -+ s->type = icapServiceToType(s->type_name); -+ if (s->type >= ICAP_SERVICE_MAX) { -+ debug(3, 0) ("icap_service_process (line %d): wrong service type %s\n", config_lineno, s->type_name); -+ return 0; -+ } -+ if (s->type == ICAP_SERVICE_REQMOD_PRECACHE) -+ s->method = ICAP_METHOD_REQMOD; -+ else if (s->type == ICAP_SERVICE_REQMOD_PRECACHE) -+ s->method = ICAP_METHOD_REQMOD; -+ else if (s->type == ICAP_SERVICE_REQMOD_POSTCACHE) -+ s->method = ICAP_METHOD_REQMOD; -+ else if (s->type == ICAP_SERVICE_RESPMOD_PRECACHE) -+ s->method = ICAP_METHOD_RESPMOD; -+ else if (s->type == ICAP_SERVICE_RESPMOD_POSTCACHE) -+ s->method = ICAP_METHOD_RESPMOD; -+ debug(3, 5) ("icap_service_process (line %d): type=%s\n", config_lineno, icapServiceToStr(s->type)); -+ if (strncmp(s->uri, "icap://", 7) != 0) { -+ debug(3, 0) ("icap_service_process (line %d): wrong uri: %s\n", config_lineno, s->uri); -+ return 0; -+ } -+ start = s->uri + 7; -+ if ((end = strchr(start, ':')) != NULL) { -+ /* ok */ -+ port_in_uri = 1; -+ debug(3, 5) ("icap_service_process (line %d): port given\n", config_lineno); -+ } else { -+ /* ok */ -+ port_in_uri = 0; -+ debug(3, 5) ("icap_service_process (line %d): no port given\n", config_lineno); -+ } -+ -+ if ((tempEnd = strchr(start, '/')) != NULL) { -+ /* ok */ -+ resource_in_uri = 1; -+ debug(3, 5) ("icap_service_process (line %d): resource given\n", config_lineno); -+ if (end == '\0') { -+ end = tempEnd; -+ } -+ } else { -+ /* ok */ -+ resource_in_uri = 0; -+ debug(3, 5) ("icap_service_process (line %d): no resource given\n", config_lineno); -+ } -+ -+ tempEnd = strchr(start, '\0'); -+ if (end == '\0') { -+ end = tempEnd; -+ } -+ len = end - start; -+ s->hostname = xstrndup(start, len + 1); -+ s->hostname[len] = 0; -+ debug(3, 5) ("icap_service_process (line %d): hostname=%s\n", config_lineno, s->hostname); -+ start = end; -+ -+ if (port_in_uri) { -+ start++; /* skip ':' */ -+ if (resource_in_uri) -+ end = strchr(start, '/'); -+ else -+ end = strchr(start, '\0'); -+ s->port = strtoul(start, &tailp, 0) % 65536; -+ if (tailp != end) { -+ debug(3, 0) ("icap_service_process (line %d): wrong service uri (port could not be parsed): %s\n", config_lineno, s->uri); -+ return 0; -+ } -+ debug(3, 5) ("icap_service_process (line %d): port=%d\n", config_lineno, s->port); -+ start = end; -+ } else { -+ /* no explicit ICAP port; first ask by getservbyname or default to -+ * hardwired port 1344 per ICAP specification section 4.2 */ -+ struct servent *serv = getservbyname("icap", "tcp"); -+ if (serv) { -+ s->port = htons(serv->s_port); -+ debug(3, 5) ("icap_service_process (line %d): default port=%d getservbyname(icap,tcp)\n", config_lineno, s->port); -+ } else { -+ s->port = 1344; -+ debug(3, 5) ("icap_service_process (line %d): default hardwired port=%d\n", config_lineno, s->port); -+ } -+ } -+ -+ if (resource_in_uri) { -+ start++; /* skip '/' */ -+ /* the rest is resource name */ -+ end = strchr(start, '\0'); -+ len = end - start; -+ if (len > 1024) { -+ debug(3, 0) ("icap_service_process (line %d): long resource name (>1024), probably wrong\n", config_lineno); -+ } -+ s->resource = xstrndup(start, len + 1); -+ s->resource[len] = 0; -+ debug(3, 5) ("icap_service_process (line %d): service=%s\n", config_lineno, s->resource); -+ } -+ /* check bypass */ -+ if ((s->bypass != 0) && (s->bypass != 1)) { -+ debug(3, 0) ("icap_service_process (line %d): invalid bypass value\n", config_lineno); -+ return 0; -+ } -+ return 1; -+} -+ -+/* -+ * constructor -+ */ -+static void -+icap_service_init(icap_service * s) -+{ -+ s->type = ICAP_SERVICE_MAX; /* means undefined */ -+ s->preview = Config.icapcfg.preview_size; -+ s->opt = 0; -+ s->keep_alive = 1; -+ s->istag = StringNull; -+ s->transfer_preview = StringNull; -+ s->transfer_ignore = StringNull; -+ s->transfer_complete = StringNull; -+} -+ -+/* -+ * destructor -+ * frees only strings, but don't touch the linked list -+ */ -+static void -+icap_service_destroy(icap_service * s) -+{ -+ xfree(s->name); -+ xfree(s->uri); -+ xfree(s->type_name); -+ xfree(s->hostname); -+ xfree(s->resource); -+ assert(s->opt == 0); /* there should be no opt request running now */ -+ stringClean(&s->istag); -+ stringClean(&s->transfer_preview); -+ stringClean(&s->transfer_ignore); -+ stringClean(&s->transfer_complete); -+} -+ -+icap_service * -+icap_service_lookup(char *name) -+{ -+ icap_service *iter; -+ for (iter = Config.icapcfg.service_head; iter; iter = iter->next) { -+ if (!strcmp(name, iter->name)) { -+ return iter; -+ } -+ } -+ return NULL; -+} -+ -+/*************************************************** -+ * icap_service_list -+ */ -+ -+static void -+icap_service_list_add(icap_service_list ** isl, char *service_name) -+{ -+ icap_service_list **iter; -+ icap_service_list *new; -+ icap_service *gbl_service; -+ int i; -+ int max_services; -+ -+ new = memAllocate(MEM_ICAP_SERVICE_LIST); -+ /* Found all services with that name, and add to the array */ -+ max_services = sizeof(new->services) / sizeof(icap_service *); -+ gbl_service = Config.icapcfg.service_head; -+ i = 0; -+ while (gbl_service && i < max_services) { -+ if (!strcmp(service_name, gbl_service->name)) -+ new->services[i++] = gbl_service; -+ gbl_service = gbl_service->next; -+ } -+ new->nservices = i; -+ -+ if (*isl) { -+ iter = isl; -+ while ((*iter)->next) -+ iter = &((*iter)->next); -+ (*iter)->next = new; -+ } else { -+ *isl = new; -+ } -+} -+ -+/* -+ * free the linked list without touching references icap_service -+ */ -+static void -+icap_service_list_destroy(icap_service_list * isl) -+{ -+ icap_service_list *current; -+ icap_service_list *next; -+ -+ current = isl; -+ while (current) { -+ next = current->next; -+ memFree(current, MEM_ICAP_SERVICE_LIST); -+ current = next; -+ } -+} -+ -+/*************************************************** -+ * icap_class -+ */ -+static void -+parse_icap_class_type(IcapConfig * cfg) -+{ -+ icap_class *s = NULL; -+ -+ s = memAllocate(MEM_ICAP_CLASS); -+ parse_string(&s->name); -+ parse_wordlist(&s->services); -+ -+ if (icap_class_process(s)) { -+ /* if ok, put into linked list */ -+ icap_class_add(s); -+ } else { -+ /* clean up structure */ -+ debug(3, 0) ("parse_icap_class_type (line %d): skipping %s\n", config_lineno, s->name); -+ icap_class_destroy(s); -+ memFree(s, MEM_ICAP_CLASS); -+ } -+} -+ -+static void -+dump_icap_class_type(StoreEntry * e, const char *name, IcapConfig cfg) -+{ -+ icap_class *current_node = NULL; -+ LOCAL_ARRAY(char, nom, 64); -+ -+ if (!cfg.class_head) { -+ storeAppendPrintf(e, "%s 0\n", name); -+ return; -+ } -+ current_node = cfg.class_head; -+ -+ while (current_node) { -+ snprintf(nom, 64, "%s %s", name, current_node->name); -+ dump_wordlist(e, nom, current_node->services); -+ current_node = current_node->next; -+ } -+} -+ -+static void -+free_icap_class_type(IcapConfig * cfg) -+{ -+ while (cfg->class_head) { -+ icap_class *current_node = cfg->class_head; -+ cfg->class_head = current_node->next; -+ icap_class_destroy(current_node); -+ memFree(current_node, MEM_ICAP_CLASS); -+ } -+} -+ -+/* -+ * process services list, return 1, if at least one service was found -+ */ -+static int -+icap_class_process(icap_class * c) -+{ -+ icap_service_list *isl = NULL; -+ wordlist *iter; -+ icap_service *service; -+ /* take services list and build icap_service_list from it */ -+ for (iter = c->services; iter; iter = iter->next) { -+ service = icap_service_lookup(iter->key); -+ if (service) { -+ icap_service_list_add(&isl, iter->key); -+ } else { -+ debug(3, 0) ("icap_class_process (line %d): skipping service %s in class %s\n", config_lineno, iter->key, c->name); -+ } -+ } -+ -+ if (isl) { -+ c->isl = isl; -+ return 1; -+ } -+ return 0; -+} -+ -+/* -+ * search for an icap_class in the global IcapConfig -+ * classes with hidden-flag are skipped -+ */ -+static icap_class * -+icap_class_lookup(char *name) -+{ -+ icap_class *iter; -+ for (iter = Config.icapcfg.class_head; iter; iter = iter->next) { -+ if ((!strcmp(name, iter->name)) && (!iter->hidden)) { -+ return iter; -+ } -+ } -+ return NULL; -+} -+ -+/* -+ * adds an icap_class to the global IcapConfig -+ */ -+static void -+icap_class_add(icap_class * c) -+{ -+ icap_class *cp = NULL; -+ icap_class **t = NULL; -+ IcapConfig *cfg = &Config.icapcfg; -+ if (c) { -+ for (cp = cfg->class_head, t = &cfg->class_head; cp; t = &cp->next, cp = cp->next); -+ *t = c; -+ } -+} -+ -+/* -+ * free allocated memory inside icap_class -+ */ -+static void -+icap_class_destroy(icap_class * c) -+{ -+ xfree(c->name); -+ wordlistDestroy(&c->services); -+ icap_service_list_destroy(c->isl); -+} -+ -+/*************************************************** -+ * icap_access -+ */ -+ -+/* format: icap_access <servicename> {allow|deny} acl, ... */ -+static void -+parse_icap_access_type(IcapConfig * cfg) -+{ -+ icap_access *A = NULL; -+ icap_access *B = NULL; -+ icap_access **T = NULL; -+ icap_service *s = NULL; -+ icap_class *c = NULL; -+ ushort no_class = 0; -+ -+ A = memAllocate(MEM_ICAP_ACCESS); -+ parse_string(&A->service_name); -+ -+ /* -+ * try to find a class with the given name first. if not found, search -+ * the services. if a service is found, create a new hidden class with -+ * only this service. this is for backward compatibility. -+ * -+ * the special classname All is allowed only in deny rules, because -+ * the class is not used there. -+ */ -+ if (!strcmp(A->service_name, "None")) { -+ no_class = 1; -+ } else { -+ A->class = icap_class_lookup(A->service_name); -+ if (!A->class) { -+ s = icap_service_lookup(A->service_name); -+ if (s) { -+ c = memAllocate(MEM_ICAP_CLASS); -+ c->name = xstrdup("(hidden)"); -+ c->hidden = 1; -+ wordlistAdd(&c->services, A->service_name); -+ c->isl = memAllocate(MEM_ICAP_SERVICE_LIST); -+ /* FIXME:luc: check what access do */ -+ c->isl->services[0] = s; -+ c->isl->nservices = 1; -+ icap_class_add(c); -+ A->class = c; -+ } else { -+ debug(3, 0) ("parse_icap_access_type (line %d): servicename %s not found. skipping.\n", config_lineno, A->service_name); -+ memFree(A, MEM_ICAP_ACCESS); -+ return; -+ } -+ } -+ } -+ -+ aclParseAccessLine(&(A->access)); -+ debug(3, 5) ("parse_icap_access_type (line %d): %s\n", config_lineno, A->service_name); -+ -+ /* check that All class is only used in deny rule */ -+ if (no_class && A->access->allow) { -+ memFree(A, MEM_ICAP_ACCESS); -+ debug(3, 0) ("parse_icap_access (line %d): special class 'None' only allowed in deny rule. skipping.\n", config_lineno); -+ return; -+ } -+ if (A->access) { -+ for (B = cfg->access_head, T = &cfg->access_head; B; T = &B->next, B = B->next); -+ *T = A; -+ } else { -+ debug(3, 0) ("parse_icap_access_type (line %d): invalid line skipped\n", config_lineno); -+ memFree(A, MEM_ICAP_ACCESS); -+ } -+} -+ -+static void -+dump_icap_access_type(StoreEntry * e, const char *name, IcapConfig cfg) -+{ -+ icap_access *current_node = NULL; -+ LOCAL_ARRAY(char, nom, 64); -+ -+ if (!cfg.access_head) { -+ storeAppendPrintf(e, "%s 0\n", name); -+ return; -+ } -+ current_node = cfg.access_head; -+ -+ while (current_node) { -+ snprintf(nom, 64, "%s %s", name, current_node->service_name); -+ dump_acl_access(e, nom, current_node->access); -+ current_node = current_node->next; -+ } -+} -+ -+static void -+free_icap_access_type(IcapConfig * cfg) -+{ -+ while (cfg->access_head) { -+ icap_access *current_node = cfg->access_head; -+ cfg->access_head = current_node->next; -+ icap_access_destroy(current_node); -+ memFree(current_node, MEM_ICAP_ACCESS); -+ } -+} -+ -+/* -+ * destructor -+ * frees everything but the linked list -+ */ -+static void -+icap_access_destroy(icap_access * a) -+{ -+ xfree(a->service_name); -+ aclDestroyAccessList(&a->access); -+} -+ -+/*************************************************** -+ * for debugging purposes only -+ */ -+void -+dump_icap_config(IcapConfig * cfg) -+{ -+ icap_service *s_iter; -+ icap_class *c_iter; -+ icap_access *a_iter; -+ icap_service_list *isl_iter; -+ acl_list *l; -+ debug(3, 0) ("IcapConfig: onoff = %d\n", cfg->onoff); -+ debug(3, 0) ("IcapConfig: service_head = %d\n", (int) cfg->service_head); -+ debug(3, 0) ("IcapConfig: class_head = %d\n", (int) cfg->class_head); -+ debug(3, 0) ("IcapConfig: access_head = %d\n", (int) cfg->access_head); -+ -+ debug(3, 0) ("IcapConfig: services =\n"); -+ for (s_iter = cfg->service_head; s_iter; s_iter = s_iter->next) { -+ printf(" %s: \n", s_iter->name); -+ printf(" bypass = %d\n", s_iter->bypass); -+ printf(" hostname = %s\n", s_iter->hostname); -+ printf(" port = %d\n", s_iter->port); -+ printf(" resource = %s\n", s_iter->resource); -+ } -+ debug(3, 0) ("IcapConfig: classes =\n"); -+ for (c_iter = cfg->class_head; c_iter; c_iter = c_iter->next) { -+ printf(" %s: \n", c_iter->name); -+ printf(" services = \n"); -+ for (isl_iter = c_iter->isl; isl_iter; isl_iter = isl_iter->next) { -+ int i; -+ for (i = 0; i < isl_iter->nservices; i++) -+ printf(" %s\n", isl_iter->services[i]->name); -+ } -+ } -+ debug(3, 0) ("IcapConfig: access =\n"); -+ for (a_iter = cfg->access_head; a_iter; a_iter = a_iter->next) { -+ printf(" service_name = %s\n", a_iter->service_name); -+ printf(" access = %s", a_iter->access->allow ? "allow" : "deny"); -+ for (l = a_iter->access->acl_list; l != NULL; l = l->next) { -+ printf(" %s%s", -+ l->op ? null_string : "!", -+ l->acl->name); -+ } -+ printf("\n"); -+ } -+} -+#endif /* HS_FEAT_ICAP */ - - static void - parse_kb_size_t(squid_off_t * var) -Index: src/cbdata.c -=================================================================== -RCS file: /cvsroot/squid/squid/src/cbdata.c,v -retrieving revision 1.14.6.1 -retrieving revision 1.14.32.2 -diff -p -u -b -r1.14.6.1 -r1.14.32.2 ---- src/cbdata.c 17 Jul 2003 02:13:28 -0000 1.14.6.1 -+++ src/cbdata.c 14 Sep 2003 01:36:26 -0000 1.14.32.2 -@@ -144,6 +144,10 @@ cbdataInit(void) - CREATE_CBDATA(statefulhelper); - CREATE_CBDATA(helper_stateful_server); - CREATE_CBDATA(HttpStateData); -+#ifdef HS_FEAT_ICAP -+ CREATE_CBDATA(IcapStateData); -+ CREATE_CBDATA(icap_service); -+#endif - CREATE_CBDATA_FREE(peer, peerDestroy); - CREATE_CBDATA(ps_state); - CREATE_CBDATA(RemovalPolicy); -Index: src/cf.data.pre -=================================================================== -RCS file: /cvsroot/squid/squid/src/cf.data.pre,v -retrieving revision 1.49.2.84 -retrieving revision 1.49.2.33.2.32 -diff -p -u -b -r1.49.2.84 -r1.49.2.33.2.32 ---- src/cf.data.pre 21 Oct 2005 02:13:47 -0000 1.49.2.84 -+++ src/cf.data.pre 24 Oct 2005 17:07:42 -0000 1.49.2.33.2.32 -@@ -2397,7 +2397,6 @@ DOC_START - ensure correct results it is best to set server_persisten_connections - to off when using this directive in such configurations. - DOC_END -- - NAME: reply_header_max_size - COMMENT: (KB) - TYPE: b_size_t -@@ -2716,6 +2715,177 @@ DOC_START - DOC_END - - COMMENT_START -+ ICAP OPTIONS -+ ----------------------------------------------------------------------------- -+COMMENT_END -+ -+NAME: icap_enable -+TYPE: onoff -+IFDEF: HS_FEAT_ICAP -+COMMENT: on|off -+LOC: Config.icapcfg.onoff -+DEFAULT: off -+DOC_START -+ If you want to enable the ICAP client module, set this to on. -+DOC_END -+ -+NAME: icap_preview_enable -+TYPE: onoff -+IFDEF: HS_FEAT_ICAP -+COMMENT: on|off -+LOC: Config.icapcfg.preview_enable -+DEFAULT: off -+DOC_START -+ Set this to 'on' if you want to enable the ICAP preview -+ feature in Squid. -+DOC_END -+ -+NAME: icap_preview_size -+TYPE: int -+IFDEF: HS_FEAT_ICAP -+LOC: Config.icapcfg.preview_size -+DEFAULT: -1 -+DOC_START -+ The default size of preview data to be sent to the ICAP server. -+ -1 means no preview. This value might be overwritten on a per server -+ basis by OPTIONS requests. -+DOC_END -+ -+NAME: icap_check_interval -+TYPE: int -+IFDEF: HS_FEAT_ICAP -+LOC: Config.icapcfg.check_interval -+DEFAULT: 300 -+DOC_START -+ If an ICAP server does not respond, it gets marked as unreachable. Squid -+ will try again to reach it after this time. -+DOC_END -+ -+NAME: icap_send_client_ip -+TYPE: onoff -+IFDEF: HS_FEAT_ICAP -+COMMENT: on|off -+LOC: Config.icapcfg.send_client_ip -+DEFAULT: off -+DOC_START -+ This adds the header "X-Client-IP" to ICAP requests. Can also be -+ set from the server'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 -+ This adds the header "X-Authenticated-User" to ICAP requests -+ if proxy access is authentified. Can also be set from the server's -+ response to OPTIONS. -+DOC_END -+ -+NAME: icap_auth_scheme -+TYPE: string -+IFDEF: HS_FEAT_ICAP -+LOC: Config.icapcfg.auth_scheme -+DEFAULT: Local://%u -+DOC_START -+ Authentification scheme to pass to ICAP requests if -+ icap_send_auth_user is enabled. The first occurence of "%u" -+ is replaced by the authentified user name. If no "%u" is found, -+ the username is added at the end of the scheme. -+ -+ See http://www.ietf.org/internet-drafts/draft-stecher-icap-subid-00.txt, -+ section 3.4 for details on this. -+ -+ Examples: -+ -+ icap_auth_scheme Local://%u -+ icap_auth_scheme LDAP://ldap-server/cn=%u,dc=company,dc=com -+ icap_auth_scheme WinNT://nt-domain/%u -+ icap_auth_scheme Radius://radius-server/%u -+DOC_END -+ -+NAME: icap_service -+TYPE: icap_service_type -+IFDEF: HS_FEAT_ICAP -+LOC: Config.icapcfg -+DEFAULT: none -+DOC_START -+ Defines a single ICAP service -+ -+ icap_service servicename vectoring_point bypass service_url [options ...] -+ -+ vectoring_point = reqmod_precache|reqmod_postcache|respmod_precache|respmod_postcache -+ This specifies at which point of request processing the ICAP -+ service should be plugged in. -+ bypass = 1|0 -+ If set to 1 and the ICAP server cannot be reached, the request will go -+ through without being processed by an ICAP server -+ service_url = icap://servername:port/service -+ -+ Options: -+ -+ no-keep-alive To always close the connection to icap server -+ after the transaction completes -+ -+ -+ Note: reqmod_precache and respmod_postcache is not yet implemented -+ -+ Load-balancing and high availability: -+ You can obtain load-balancing and high availability by defining a -+ named service with different definitions. Then, the client -+ loops through the different entities of the service providing -+ load-balancing. If an entity is marked as unreachable, the client goes -+ one step further to the next entity: you have the high-availability. -+ See the service_1 definition below -+ -+Example: -+icap_service service_1 reqmod_precache 0 icap://icap1.mydomain.net:1344/reqmod -+icap_service service_1 reqmod_precache 0 icap://icap2.mydomain.net:1344/reqmod no-keep-alive -+icap_service service_2 respmod_precache 0 icap://icap3.mydomain.net:1344/respmod -+DOC_END -+ -+NAME: icap_class -+TYPE: icap_class_type -+IFDEF: HS_FEAT_ICAP -+LOC: Config.icapcfg -+DEFAULT: none -+DOC_START -+ Defines an ICAP service chain. If there are multiple services per -+ vectoring point, they are processed in the specified order. -+ -+ icap_class classname servicename... -+ -+Example: -+icap_class class_1 service_1 service_2 -+icap class class_2 service_1 service_3 -+DOC_END -+ -+NAME: icap_access -+TYPE: icap_access_type -+IFDEF: HS_FEAT_ICAP -+LOC: Config.icapcfg -+DEFAULT: none -+DOC_START -+ Redirects a request through an ICAP service class, depending -+ on given acls -+ -+ icap_access classname allow|deny [!]aclname... -+ -+ The icap_access statements are processed in the order they appear in -+ this configuration file. If an access list matches, the processing stops. -+ For an "allow" rule, the specified class is used for the request. A "deny" -+ rule simply stops processing without using the class. You can also use the -+ special classname "None". -+ -+ For backward compatibility, it is also possible to use services -+ directly here. -+Example: -+icap_access class_1 allow all -+DOC_END -+ -+COMMENT_START - MISCELLANEOUS - ----------------------------------------------------------------------------- - COMMENT_END -Index: src/cf_gen_defines -=================================================================== -RCS file: /cvsroot/squid/squid/src/cf_gen_defines,v -retrieving revision 1.5 -retrieving revision 1.5.48.3 -diff -p -u -b -r1.5 -r1.5.48.3 ---- src/cf_gen_defines 3 Dec 2001 08:03:21 -0000 1.5 -+++ src/cf_gen_defines 13 Mar 2005 17:58:44 -0000 1.5.48.3 -@@ -18,12 +18,13 @@ BEGIN { - define["USE_UNLINKD"]="--enable-unlinkd" - define["USE_USERAGENT_LOG"]="--enable-useragent-log" - define["USE_WCCP"]="--enable-wccp" -+ define["HS_FEAT_ICAP"]="--enable-icap-support" - } - /^IFDEF:/ { - if (define[$2] != "") -- DEFINE=define[$2] -+ DEFINE = define[$2] - else -- DEFINE="-D" $2 -+ DEFINE = "-D" $2 - print "{\"" $2 "\", \"" DEFINE "\", " - print "#if " $2 - print "1" -Index: src/client_side.c -=================================================================== -RCS file: /cvsroot/squid/squid/src/client_side.c,v -retrieving revision 1.47.2.71 -retrieving revision 1.47.2.28.2.40 -diff -p -u -b -r1.47.2.71 -r1.47.2.28.2.40 ---- src/client_side.c 19 Oct 2005 02:13:20 -0000 1.47.2.71 -+++ src/client_side.c 6 Dec 2005 21:53:44 -0000 1.47.2.28.2.40 -@@ -109,7 +109,7 @@ static const char *const crlf = "\r\n"; - static CWCB clientWriteComplete; - static CWCB clientWriteBodyComplete; - static PF clientReadRequest; --static PF connStateFree; -+PF connStateFree; - static PF requestTimeout; - static PF clientLifetimeTimeout; - static int clientCheckTransferDone(clientHttpRequest *); -@@ -136,20 +136,23 @@ static void clientSetKeepaliveFlag(clien - static void clientPackRangeHdr(const HttpReply * rep, const HttpHdrRangeSpec * spec, String boundary, MemBuf * mb); - static void clientPackTermBound(String boundary, MemBuf * mb); - static void clientInterpretRequestHeaders(clientHttpRequest *); --static void clientProcessRequest(clientHttpRequest *); -+void clientProcessRequest(clientHttpRequest *); - static void clientProcessExpired(void *data); - static void clientProcessOnlyIfCachedMiss(clientHttpRequest * http); --static int clientCachable(clientHttpRequest * http); --static int clientHierarchical(clientHttpRequest * http); --static int clientCheckContentLength(request_t * r); -+int clientCachable(clientHttpRequest * http); -+int clientHierarchical(clientHttpRequest * http); -+int clientCheckContentLength(request_t * r); - static DEFER httpAcceptDefer; - static log_type clientProcessRequest2(clientHttpRequest * http); - static int clientReplyBodyTooLarge(clientHttpRequest *, squid_off_t clen); - static int clientRequestBodyTooLarge(squid_off_t clen); - static void clientProcessBody(ConnStateData * conn); - static void clientEatRequestBody(clientHttpRequest *); --static BODY_HANDLER clientReadBody; -+BODY_HANDLER clientReadBody; - static void clientAbortBody(request_t * req); -+#if HS_FEAT_ICAP -+static int clientIcapReqMod(clientHttpRequest * http); -+#endif - - static int - checkAccelOnly(clientHttpRequest * http) -@@ -392,6 +395,10 @@ clientRedirectDone(void *data, char *res - http->request = requestLink(new_request); - } - clientInterpretRequestHeaders(http); -+#if HS_FEAT_ICAP -+ if (Config.icapcfg.onoff) -+ icapCheckAcl(http); -+#endif - #if HEADERS_LOG - headersLog(0, 1, request->method, request); - #endif -@@ -931,11 +938,22 @@ httpRequestFree(void *data) - *H = http->next; - http->next = NULL; - dlinkDelete(&http->active, &ClientActiveRequests); -+#if HS_FEAT_ICAP -+ /*In the case that the upload of data breaks, we need this code here .... */ -+ if (NULL != http->icap_reqmod) { -+ if (cbdataValid(http->icap_reqmod)) -+ if (http->icap_reqmod->icap_fd > -1) { -+ comm_close(http->icap_reqmod->icap_fd); -+ } -+ cbdataUnlock(http->icap_reqmod); -+ http->icap_reqmod = NULL; -+ } -+#endif - cbdataFree(http); - } - - /* This is a handler normally called by comm_close() */ --static void -+void - connStateFree(int fd, void *data) - { - ConnStateData *connState = data; -@@ -958,7 +976,6 @@ connStateFree(int fd, void *data) - } else - safe_free(connState->in.buf); - /* XXX account connState->in.buf */ -- pconnHistCount(0, connState->nrequests); - cbdataFree(connState); - #ifdef _SQUID_LINUX_ - /* prevent those nasty RST packets */ -@@ -1103,7 +1120,7 @@ clientSetKeepaliveFlag(clientHttpRequest - } - } - --static int -+int - clientCheckContentLength(request_t * r) - { - switch (r->method) { -@@ -1122,7 +1139,7 @@ clientCheckContentLength(request_t * r) - /* NOT REACHED */ - } - --static int -+int - clientCachable(clientHttpRequest * http) - { - request_t *req = http->request; -@@ -1148,7 +1165,7 @@ clientCachable(clientHttpRequest * http) - } - - /* Return true if we can query our neighbors for this object */ --static int -+int - clientHierarchical(clientHttpRequest * http) - { - const char *url = http->uri; -@@ -2439,7 +2456,7 @@ clientProcessRequest2(clientHttpRequest - return LOG_TCP_HIT; - } - --static void -+void - clientProcessRequest(clientHttpRequest * http) - { - char *url = http->uri; -@@ -2449,6 +2466,11 @@ clientProcessRequest(clientHttpRequest * - debug(33, 4) ("clientProcessRequest: %s '%s'\n", - RequestMethodStr[r->method], - url); -+#if HS_FEAT_ICAP -+ if (clientIcapReqMod(http)) { -+ return; -+ } -+#endif - if (r->method == METHOD_CONNECT && !http->redirect.status) { - http->log_type = LOG_TCP_MISS; - sslStart(http, &http->out.size, &http->al.http.code); -@@ -2993,6 +3015,20 @@ clientReadRequest(int fd, void *data) - (long) conn->in.offset, (long) conn->in.size); - len = conn->in.size - conn->in.offset - 1; - } -+#if HS_FEAT_ICAP -+ /* -+ * This check exists because ICAP doesn't always work well -+ * with persistent (reused) connections. One version of the -+ * REQMOD code creates a fake ConnStateData, which doesn't have -+ * an in.buf. We want to make sure that the fake ConnStateData -+ * doesn't get used here. -+ */ -+ if (NULL == conn->in.buf) { -+ debug(33, 1) ("clientReadRequest: FD %d aborted; conn->in.buf is NULL\n", fd); -+ comm_close(fd); -+ return; -+ } -+#endif - statCounter.syscalls.sock.reads++; - size = FD_READ_METHOD(fd, conn->in.buf + conn->in.offset, len); - if (size > 0) { -@@ -3096,7 +3132,8 @@ clientReadRequest(int fd, void *data) - /* add to the client request queue */ - for (H = &conn->chr; *H; H = &(*H)->next); - *H = http; -- conn->nrequests++; -+ F->pconn.uses++; -+ F->pconn.type = 0; - /* - * I wanted to lock 'http' here since its callback data for - * clientLifetimeTimeout(), but there's no logical place to -@@ -3266,7 +3303,7 @@ clientReadRequest(int fd, void *data) - } - - /* file_read like function, for reading body content */ --static void -+void - clientReadBody(request_t * request, char *buf, size_t size, CBCB * callback, void *cbdata) - { - ConnStateData *conn = request->body_reader_data; -@@ -3390,7 +3427,7 @@ clientProcessBody(ConnStateData * conn) - } - - /* Abort a body request */ --static void -+void - clientAbortBody(request_t * request) - { - ConnStateData *conn = request->body_reader_data; -@@ -3432,7 +3469,7 @@ requestTimeout(int fd, void *data) - * Some data has been sent to the client, just close the FD - */ - comm_close(fd); -- } else if (conn->nrequests) { -+ } else if (fd_table[fd].pconn.uses) { - /* - * assume its a persistent connection; just close it - */ -@@ -3948,3 +3985,49 @@ varyEvaluateMatch(StoreEntry * entry, re - } - } - } -+ -+#if HS_FEAT_ICAP -+static int -+clientIcapReqMod(clientHttpRequest * http) -+{ -+ ErrorState *err; -+ icap_service *service; -+ if (http->flags.did_icap_reqmod) -+ return 0; -+ if (NULL == (service = icapService(ICAP_SERVICE_REQMOD_PRECACHE, http->request))) -+ return 0; -+ debug(33, 3) ("clientIcapReqMod: calling icapReqModStart for %p\n", http); -+ /* -+ * Note, we pass 'start' and 'log_addr' to ICAP so the access.log -+ * entry comes out right. The 'clientHttpRequest' created by -+ * the ICAP side is the one that gets logged. The first -+ * 'clientHttpRequest' does not get logged because its out.size -+ * is zero and log_type is unset. -+ */ -+ http->icap_reqmod = icapReqModStart(service, -+ http->uri, -+ http->request, -+ http->conn->fd, -+ http->start, -+ http->conn->log_addr, -+ (void *) http->conn); -+ if (NULL == http->icap_reqmod) { -+ return 0; -+ } else if (-1 == (int) http->icap_reqmod) { -+ /* produce error */ -+ http->icap_reqmod = NULL; -+ debug(33, 2) ("clientIcapReqMod: icap told us to send an error\n"); -+ http->log_type = LOG_TCP_DENIED; -+ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR); -+ err->xerrno = ETIMEDOUT; -+ err->request = requestLink(http->request); -+ err->src_addr = http->conn->peer.sin_addr; -+ http->entry = clientCreateStoreEntry(http, http->request->method, null_request_flags); -+ errorAppendEntry(http->entry, err); -+ return 1; -+ } -+ cbdataLock(http->icap_reqmod); -+ http->flags.did_icap_reqmod = 1; -+ return 1; -+} -+#endif -Index: src/comm.c -=================================================================== -RCS file: /cvsroot/squid/squid/src/comm.c,v -retrieving revision 1.18.6.6 -retrieving revision 1.18.6.2.12.9 -diff -p -u -b -r1.18.6.6 -r1.18.6.2.12.9 ---- src/comm.c 11 Sep 2005 02:13:22 -0000 1.18.6.6 -+++ src/comm.c 23 Nov 2005 20:33:06 -0000 1.18.6.2.12.9 -@@ -653,8 +653,8 @@ comm_close(int fd) - #endif - 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) { - SSL_free(F->ssl); -Index: src/enums.h -=================================================================== -RCS file: /cvsroot/squid/squid/src/enums.h,v -retrieving revision 1.29.2.18 -retrieving revision 1.29.2.8.2.17 -diff -p -u -b -r1.29.2.18 -r1.29.2.8.2.17 ---- src/enums.h 12 Nov 2005 03:13:48 -0000 1.29.2.18 -+++ src/enums.h 23 Nov 2005 20:38:56 -0000 1.29.2.8.2.17 -@@ -93,6 +93,7 @@ typedef enum { - ERR_ONLY_IF_CACHED_MISS, /* failure to satisfy only-if-cached request */ - ERR_TOO_BIG, - TCP_RESET, -+ ERR_ICAP_FAILURE, - ERR_INVALID_RESP, - ERR_MAX - } err_type; -@@ -438,6 +439,9 @@ typedef enum { - PROTO_WHOIS, - PROTO_INTERNAL, - PROTO_HTTPS, -+#if HS_FEAT_ICAP -+ PROTO_ICAP, -+#endif - PROTO_MAX - } protocol_t; - -@@ -610,6 +614,12 @@ typedef enum { - MEM_TLV, - MEM_SWAP_LOG_DATA, - MEM_CLIENT_REQ_BUF, -+#if HS_FEAT_ICAP -+ MEM_ICAP_OPT_DATA, -+ MEM_ICAP_SERVICE_LIST, -+ MEM_ICAP_CLASS, -+ MEM_ICAP_ACCESS, -+#endif - MEM_MAX - } mem_type; - -@@ -709,9 +719,14 @@ typedef enum { - CBDATA_RemovalPolicyWalker, - CBDATA_RemovalPurgeWalker, - CBDATA_store_client, -+#ifdef HS_FEAT_ICAP -+ CBDATA_IcapStateData, -+ CBDATA_icap_service, -+#endif - CBDATA_FIRST_CUSTOM_TYPE = 1000 - } cbdata_type; - -+ - /* - * Return codes from checkVary(request) - */ -@@ -742,4 +757,68 @@ enum { - - #endif - -+#if HS_FEAT_ICAP -+typedef enum { -+ ICAP_STATUS_NONE = 0, -+ ICAP_STATUS_CONTINUE = 100, -+ ICAP_STATUS_SWITCHING_PROTOCOLS = 101, -+ ICAP_STATUS_STATUS_OK = 200, -+ ICAP_CREATED = 201, -+ ICAP_STATUS_ACCEPTED = 202, -+ ICAP_STATUS_NON_AUTHORITATIVE_INFORMATION = 203, -+ ICAP_STATUS_NO_MODIFICATION_NEEDED = 204, -+ ICAP_STATUS_RESET_CONTENT = 205, -+ ICAP_STATUS_PARTIAL_CONTENT = 206, -+ ICAP_STATUS_MULTIPLE_CHOICES = 300, -+ ICAP_STATUS_MOVED_PERMANENTLY = 301, -+ ICAP_STATUS_MOVED_TEMPORARILY = 302, -+ ICAP_STATUS_SEE_OTHER = 303, -+ ICAP_STATUS_NOT_MODIFIED = 304, -+ ICAP_STATUS_USE_PROXY = 305, -+ ICAP_STATUS_BAD_REQUEST = 400, -+ ICAP_STATUS_UNAUTHORIZED = 401, -+ ICAP_STATUS_PAYMENT_REQUIRED = 402, -+ ICAP_STATUS_FORBIDDEN = 403, -+ ICAP_STATUS_SERVICE_NOT_FOUND = 404, -+ ICAP_STATUS_METHOD_NOT_ALLOWED = 405, -+ ICAP_STATUS_NOT_ACCEPTABLE = 406, -+ ICAP_STATUS_PROXY_AUTHENTICATION_REQUIRED = 407, -+ ICAP_STATUS_REQUEST_TIMEOUT = 408, -+ ICAP_STATUS_CONFLICT = 409, -+ ICAP_STATUS_GONE = 410, -+ ICAP_STATUS_LENGTH_REQUIRED = 411, -+ ICAP_STATUS_PRECONDITION_FAILED = 412, -+ ICAP_STATUS_REQUEST_ENTITY_TOO_LARGE = 413, -+ ICAP_STATUS_REQUEST_URI_TOO_LARGE = 414, -+ ICAP_STATUS_UNSUPPORTED_MEDIA_TYPE = 415, -+ ICAP_STATUS_INTERNAL_SERVER_ERROR = 500, -+ ICAP_STATUS_NOT_IMPLEMENTED = 501, -+ ICAP_STATUS_BAD_GATEWAY = 502, -+ ICAP_STATUS_SERVICE_OVERLOADED = 503, -+ ICAP_STATUS_GATEWAY_TIMEOUT = 504, -+ ICAP_STATUS_ICAP_VERSION_NOT_SUPPORTED = 505, -+ ICAP_STATUS_INVALID_HEADER = 600 -+} icap_status; -+ -+/* -+ * these values are used as index in an array, so it seems to be better to -+ * assign some numbers -+ */ -+typedef enum { -+ ICAP_SERVICE_REQMOD_PRECACHE = 0, -+ ICAP_SERVICE_REQMOD_POSTCACHE = 1, -+ ICAP_SERVICE_RESPMOD_PRECACHE = 2, -+ ICAP_SERVICE_RESPMOD_POSTCACHE = 3, -+ ICAP_SERVICE_MAX = 4 -+} icap_service_t; -+ -+typedef enum { -+ ICAP_METHOD_NONE, -+ ICAP_METHOD_OPTION, -+ ICAP_METHOD_REQMOD, -+ ICAP_METHOD_RESPMOD -+} icap_method_t; -+ -+#endif /* HS_FEAT_ICAP */ -+ - #endif /* SQUID_ENUMS_H */ -Index: src/forward.c -=================================================================== -RCS file: /cvsroot/squid/squid/src/forward.c,v -retrieving revision 1.13.6.15 -retrieving revision 1.13.6.3.2.15 -diff -p -u -b -r1.13.6.15 -r1.13.6.3.2.15 ---- src/forward.c 2 Sep 2005 02:13:43 -0000 1.13.6.15 -+++ src/forward.c 30 Nov 2005 21:52:15 -0000 1.13.6.3.2.15 -@@ -262,7 +262,8 @@ fwdConnectDone(int server_fd, int status - else - hierarchyNote(&fwdState->request->hier, fs->code, request->host); - fd_note(server_fd, storeUrl(fwdState->entry)); -- fd_table[server_fd].uses++; -+ fd_table[server_fd].pconn.uses++; -+ fd_table[server_fd].pconn.type = 1; - if (fs->peer) - peerConnectSucceded(fs->peer); - fwdDispatch(fwdState); -@@ -704,6 +705,8 @@ fwdCheckDeferRead(int fd, void *data) - void - fwdFail(FwdState * fwdState, ErrorState * errorState) - { -+ if (NULL == fwdState) -+ return; - debug(17, 3) ("fwdFail: %s \"%s\"\n\t%s\n", - err_type_str[errorState->type], - httpStatusString(errorState->http_status), -@@ -742,6 +745,8 @@ fwdPeerClosed(int fd, void *data) - void - fwdUnregister(int fd, FwdState * fwdState) - { -+ if (NULL == fwdState) -+ return; - debug(17, 3) ("fwdUnregister: %s\n", storeUrl(fwdState->entry)); - assert(fd == fwdState->server_fd); - assert(fd > -1); -@@ -758,7 +763,10 @@ fwdUnregister(int fd, FwdState * fwdStat - void - fwdComplete(FwdState * fwdState) - { -- StoreEntry *e = fwdState->entry; -+ StoreEntry *e; -+ if (NULL == fwdState) -+ return; -+ e = fwdState->entry; - assert(e->store_status == STORE_PENDING); - debug(17, 3) ("fwdComplete: %s\n\tstatus %d\n", storeUrl(e), - e->mem_obj->reply->sline.status); -Index: src/globals.h -=================================================================== -RCS file: /cvsroot/squid/squid/src/globals.h,v -retrieving revision 1.14.6.7 -retrieving revision 1.14.6.3.2.5 -diff -p -u -b -r1.14.6.7 -r1.14.6.3.2.5 ---- src/globals.h 14 Jun 2005 02:15:00 -0000 1.14.6.7 -+++ src/globals.h 12 Sep 2005 18:34:41 -0000 1.14.6.3.2.5 -@@ -165,6 +165,9 @@ extern char *WIN32_OS_string; /* NULL */ - #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 */ - -Index: src/http.c -=================================================================== -RCS file: /cvsroot/squid/squid/src/http.c,v -retrieving revision 1.17.6.32 -retrieving revision 1.17.6.3.6.39 -diff -p -u -b -r1.17.6.32 -r1.17.6.3.6.39 ---- src/http.c 19 Oct 2005 02:13:21 -0000 1.17.6.32 -+++ src/http.c 23 Nov 2005 20:33:07 -0000 1.17.6.3.6.39 -@@ -47,7 +47,7 @@ static CWCB httpSendRequestEntry; - - static PF httpReadReply; - static void httpSendRequest(HttpStateData *); --static PF httpStateFree; -+PF httpStateFree; - static PF httpTimeout; - static void httpCacheNegatively(StoreEntry *); - static void httpMakePrivate(StoreEntry *); -@@ -55,11 +55,12 @@ static void httpMakePublic(StoreEntry *) - static int httpCachableReply(HttpStateData *); - static void httpMaybeRemovePublic(StoreEntry *, http_status); - --static void -+void - httpStateFree(int fd, void *data) - { - HttpStateData *httpState = data; - #if DELAY_POOLS -+ if (fd >= 0) - delayClearNoDelay(fd); - #endif - if (httpState == NULL) -@@ -79,6 +80,9 @@ httpStateFree(int fd, void *data) - requestUnlink(httpState->orig_request); - httpState->request = NULL; - httpState->orig_request = NULL; -+#if HS_FEAT_ICAP -+ cbdataUnlock(httpState->icap_writer); -+#endif - cbdataFree(httpState); - } - -@@ -392,7 +396,7 @@ httpMakeVaryMark(request_t * request, Ht - } - - /* rewrite this later using new interfaces @?@ */ --static void -+void - httpProcessReplyHeader(HttpStateData * httpState, const char *buf, int size) - { - StoreEntry *entry = httpState->entry; -@@ -527,24 +531,35 @@ httpPconnTransferDone(HttpStateData * ht - MemObject *mem = httpState->entry->mem_obj; - HttpReply *reply = mem->reply; - squid_off_t clen; -+ squid_off_t content_bytes_read; - debug(11, 3) ("httpPconnTransferDone: FD %d\n", httpState->fd); - debug(11, 5) ("httpPconnTransferDone: content_length=%" PRINTF_OFF_T "\n", - reply->content_length); - /* If we haven't seen the end of reply headers, we are not done */ -- if (httpState->reply_hdr_state < 2) -+ if (httpState->reply_hdr_state < 2) { -+ debug(11, 3) ("httpPconnTransferDone: reply_hdr_state=%d, returning 0\n", -+ httpState->reply_hdr_state); - return 0; -+ } - clen = httpReplyBodySize(httpState->request->method, reply); -+#ifdef HS_FEAT_ICAP -+ if (httpState->icap_writer) { -+ content_bytes_read = httpState->icap_writer->fake_content_length; -+ debug(11, 3) ("using fake conten length %" PRINTF_OFF_T "\n", content_bytes_read); -+ } else -+#endif -+ content_bytes_read = mem->inmem_hi; - /* If the body size is unknown we must wait for EOF */ - if (clen < 0) - return 0; - /* Barf if we got more than we asked for */ -- if (mem->inmem_hi > clen + reply->hdr_sz) -+ if (content_bytes_read > clen + reply->hdr_sz) - return -1; - /* If there is no message body, we can be persistent */ - if (0 == clen) - return 1; - /* If the body size is known, we must wait until we've gotten all of it. */ -- if (mem->inmem_hi < clen + reply->hdr_sz) -+ if (content_bytes_read < clen + reply->hdr_sz) - return 0; - /* We got it all */ - return 1; -@@ -568,6 +583,17 @@ httpReadReply(int fd, void *data) - delay_id delay_id; - #endif - -+#if HS_FEAT_ICAP -+ if (httpState->icap_writer) { -+ if (!httpState->icap_writer->respmod.entry) { -+ debug(11, 3) ("httpReadReply: FD: %d: icap respmod aborded!\n", fd); -+ comm_close(fd); -+ return; -+ } -+ /*The folowing entry can not be marked as aborted. -+ * The StoreEntry icap_writer->respmod.entry used when the icap_write used...... */ -+ } else -+#endif - if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) { - comm_close(fd); - return; -@@ -579,6 +605,33 @@ httpReadReply(int fd, void *data) - else - delay_id = delayMostBytesAllowed(entry->mem_obj, &read_sz); - #endif -+ -+#if HS_FEAT_ICAP -+ if (httpState->icap_writer) { -+ IcapStateData *icap = httpState->icap_writer; -+ /* -+ * Ok we have a received a response from the web server, so try to -+ * connect the icap server if it's the first attemps. If we try -+ * to connect to the icap server, defer this request (do not read -+ * the buffer), and defer until icapConnectOver() is not called. -+ */ -+ if (icap->flags.connect_requested == 0) { -+ debug(81, 2) ("icapSendRespMod: Create a new connection to icap server\n"); -+ if (!icapConnect(icap, icapConnectOver)) { -+ debug(81, 2) ("icapSendRespMod: Something strange while creating a socket to icap server\n"); -+ commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0); -+ return; -+ } -+ debug(81, 2) ("icapSendRespMod: new connection to icap server (using FD=%d)\n", icap->icap_fd); -+ icap->flags.connect_requested = 1; -+ /* Wait for more data or EOF condition */ -+ commSetTimeout(fd, httpState->flags.keepalive_broken ? 10 : Config.Timeout.read, NULL, NULL); -+ commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0); -+ return; -+ } -+ } -+#endif -+ - errno = 0; - statCounter.syscalls.sock.reads++; - len = FD_READ_METHOD(fd, buf, read_sz); -@@ -595,7 +648,13 @@ httpReadReply(int fd, void *data) - clen >>= 1; - IOStats.Http.read_hist[bin]++; - } -- if (!httpState->reply_hdr.size && len > 0 && fd_table[fd].uses > 1) { -+#ifdef HS_FEAT_ICAP -+ if (httpState->icap_writer) -+ (void) 0; -+ else -+#endif -+ -+ if (!httpState->reply_hdr.size && len > 0 && fd_table[fd].pconn.uses > 1) { - /* Skip whitespace */ - while (len > 0 && xisspace(*buf)) - xmemmove(buf, buf + 1, len--); -@@ -625,6 +684,12 @@ httpReadReply(int fd, void *data) - } else if (len == 0) { - /* Connection closed; retrieval done. */ - httpState->eof = 1; -+#ifdef HS_FEAT_ICAP -+ if (httpState->icap_writer && cbdataValid(httpState->icap_writer)) { -+ debug(81, 3) ("httpReadReply: EOF for ICAP writer\n"); -+ icapSendRespMod(httpState->icap_writer, buf, len, 1); -+ } -+#endif - if (httpState->reply_hdr_state < 2) - /* - * Yes Henrik, there is a point to doing this. When we -@@ -677,7 +742,28 @@ httpReadReply(int fd, void *data) - EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT); - } - } -+#ifdef HS_FEAT_ICAP -+ if (httpState->icap_writer) { -+ debug(81, 5) ("calling icapSendRespMod from %s:%d\n", __FILE__, __LINE__); -+ if (cbdataValid(httpState->icap_writer)) { -+ icapSendRespMod(httpState->icap_writer, buf, len, 0); -+ httpState->icap_writer->fake_content_length += len; -+ } -+ } else -+#endif - storeAppend(entry, buf, len); -+ -+ -+ debug(11, 5) ("httpReadReply: after storeAppend FD %d read %d\n", fd, len); -+#if HS_FEAT_ICAP -+ if (httpState->icap_writer) { -+ if (!httpState->icap_writer->respmod.entry) { -+ debug(11, 3) ("httpReadReply: FD: %d: icap respmod aborded!\n", fd); -+ comm_close(fd); -+ return; -+ } -+ } else -+#endif - if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) { - /* - * the above storeAppend() call could ABORT this entry, -@@ -724,10 +810,21 @@ httpReadReply(int fd, void *data) - ("httpReadReply: Excess data from \"%s %s\"\n", - RequestMethodStr[httpState->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) { - /* yes we have to clear all these! */ - commSetDefer(fd, NULL, NULL); -@@ -766,6 +863,10 @@ httpReadReply(int fd, void *data) - ("httpReadReply: Excess data from \"%s %s\"\n", - RequestMethodStr[httpState->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; -@@ -776,6 +877,34 @@ httpReadReply(int fd, void *data) - } - } - -+#ifdef HS_FEAT_ICAP -+static int -+httpReadReplyWaitForIcap(int fd, void *data) -+{ -+ HttpStateData *httpState = data; -+ if (NULL == httpState->icap_writer) -+ return 0; -+ /* -+ * Do not defer when we are not connected to the icap server. -+ * Defer when the icap server connection is not established but pending -+ * Defer when the icap server is busy (writing on the socket) -+ */ -+ debug(11, 5) ("httpReadReplyWaitForIcap: FD %d, connect_requested=%d\n", -+ fd, httpState->icap_writer->flags.connect_requested); -+ if (!httpState->icap_writer->flags.connect_requested) -+ return 0; -+ debug(11, 5) ("httpReadReplyWaitForIcap: FD %d, connect_pending=%d\n", -+ fd, httpState->icap_writer->flags.connect_pending); -+ if (httpState->icap_writer->flags.connect_pending) -+ return 1; -+ debug(11, 5) ("httpReadReplyWaitForIcap: FD %d, write_pending=%d\n", -+ fd, httpState->icap_writer->flags.write_pending); -+ if (httpState->icap_writer->flags.write_pending) -+ return 1; -+ return 0; -+} -+#endif -+ - /* This will be called when request write is complete. Schedule read of - * reply. */ - static void -@@ -803,6 +932,63 @@ httpSendComplete(int fd, char *bufnotuse - comm_close(fd); - return; - } else { -+ /* Schedule read reply. */ -+#ifdef HS_FEAT_ICAP -+ if (icapService(ICAP_SERVICE_RESPMOD_PRECACHE, httpState->orig_request)) { -+ httpState->icap_writer = icapRespModStart( -+ ICAP_SERVICE_RESPMOD_PRECACHE, -+ httpState->orig_request, httpState->entry, httpState->flags); -+ if (-1 == (int) httpState->icap_writer) { -+ /* TODO: send error here and exit */ -+ ErrorState *err; -+ httpState->icap_writer = 0; -+ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR); -+ err->xerrno = errno; -+ err->request = requestLink(httpState->orig_request); -+ errorAppendEntry(entry, err); -+ comm_close(fd); -+ return; -+ } else if (httpState->icap_writer) { -+ request_flags fake_flags = httpState->orig_request->flags; -+ method_t fake_method = entry->mem_obj->method; -+ const char *fake_msg = "this is a fake entry for " -+ " response sent to an ICAP RESPMOD server"; -+ cbdataLock(httpState->icap_writer); -+ /* -+ * this httpState will give the data it reads to -+ * the icap server, rather than put it into -+ * a StoreEntry -+ */ -+ storeUnlockObject(httpState->entry); -+ storeUnregisterAbort(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 -@@ -811,8 +997,18 @@ httpSendComplete(int fd, char *bufnotuse - * the timeout for POST/PUT requests that have very large - * request bodies. - */ -+ -+ /* removed in stable5: -+ * commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0); -+ */ - commSetTimeout(fd, Config.Timeout.read, httpTimeout, httpState); -- commSetDefer(fd, fwdCheckDeferRead, entry); -+#ifdef HS_FEAT_ICAP -+ if (httpState->icap_writer) { -+ debug(11, 5) ("FD %d, setting httpReadReplyWaitForIcap\n", httpState->fd); -+ commSetDefer(httpState->fd, httpReadReplyWaitForIcap, httpState); -+ } else -+#endif -+ commSetDefer(httpState->fd, fwdCheckDeferRead, entry); - } - httpState->flags.request_sent = 1; - } -@@ -1010,8 +1206,11 @@ httpBuildRequestHeader(request_t * reque - if (!EBIT_TEST(cc->mask, CC_MAX_AGE)) { - const char *url = entry ? storeUrl(entry) : urlCanonical(orig_request); - httpHdrCcSetMaxAge(cc, getMaxAge(url)); -+#ifndef HS_FEAT_ICAP -+ /* Don;t bother - if the url you want to cache is redirected? */ - if (strLen(request->urlpath)) - assert(strstr(url, strBuf(request->urlpath))); -+#endif - } - /* Set no-cache if determined needed but not found */ - if (orig_request->flags.nocache && !httpHeaderHas(hdr_in, HDR_PRAGMA)) -@@ -1119,6 +1318,7 @@ httpStart(FwdState * fwd) - int fd = fwd->server_fd; - HttpStateData *httpState; - request_t *proxy_req; -+ /* ErrorState *err; */ - request_t *orig_req = fwd->request; - debug(11, 3) ("httpStart: \"%s %s\"\n", - RequestMethodStr[orig_req->method], -@@ -1156,12 +1356,22 @@ httpStart(FwdState * fwd) - httpState->request = requestLink(orig_req); - httpState->orig_request = requestLink(orig_req); - } -+#ifdef HS_FEAT_ICAP -+ if (icapService(ICAP_SERVICE_REQMOD_POSTCACHE, httpState->orig_request)) { -+ httpState->icap_writer = icapRespModStart(ICAP_SERVICE_REQMOD_POSTCACHE, -+ httpState->orig_request, httpState->entry, httpState->flags); -+ if (httpState->icap_writer) { -+ return; -+ } -+ } -+#endif - /* - * register the handler to free HTTP state data when the FD closes - */ - comm_add_close_handler(fd, httpStateFree, httpState); - statCounter.server.all.requests++; - statCounter.server.http.requests++; -+ - httpSendRequest(httpState); - /* - * We used to set the read timeout here, but not any more. -Index: src/icap_common.c -=================================================================== -RCS file: src/icap_common.c -diff -N src/icap_common.c ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ src/icap_common.c 22 Nov 2005 22:41:48 -0000 1.1.2.39 -@@ -0,0 +1,785 @@ -+/* -+ * $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); -+ 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); -+} -Index: src/icap_opt.c -=================================================================== -RCS file: src/icap_opt.c -diff -N src/icap_opt.c ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ src/icap_opt.c 22 Nov 2005 22:41:48 -0000 1.1.2.17 -@@ -0,0 +1,519 @@ -+ -+/* -+ * $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-Authenticated-User")) { -+ debug(81, 5) ("icapOptParseEntry: X-Include: found X-Authenticated-User\n"); -+ s->flags.need_x_authenticated_user = 1; -+ } -+ } else { -+ debug(81, 5) ("icapOptParseEntry: unknown options header\n"); -+ } -+} -+ -+/* parse OPTIONS reply */ -+static int -+icapOptParseReply(icap_service * s, IcapOptData * i) -+{ -+ int version_major, version_minor; -+ const char *str_status; -+ int status; -+ const char *buf = i->buf; -+ const char *parse_start; -+ const char *head_end; -+ const char *blk_start; -+ const char *blk_end; -+ -+ if ((status = -+ icapParseStatusLine(i->buf, i->offset, -+ &version_major, &version_minor, &str_status)) < 0) { -+ debug(81, 2) ("icapOptParseReply: bad status line <%s>\n", i->buf); -+ return 0; -+ } -+ debug(81, 3) ("icapOptParseReply: got reply: <ICAP/%d.%d %d %s>\n", version_major, version_minor, status, str_status); -+ -+ if (status != 200) { -+ debug(81, 3) ("icapOptParseReply: status = %d != 200\n", status); -+ return 0; -+ } -+ parse_start = buf; -+ if (i->headlen == 0) -+ i->headlen = headersEnd(parse_start, s->opt->offset); -+ -+ if (!i->headlen) { -+ debug(81, 2) ("icapOptParseReply: end of headers could not be found\n"); -+ return 0; -+ } -+ head_end = parse_start + i->headlen - 1; -+ while (*(head_end - 1) == '\r') -+ head_end--; -+ assert(*(head_end - 1) == '\n'); -+ if (*head_end != '\r' && *head_end != '\n') -+ return 0; /* failure */ -+ -+ /* skip status line */ -+ if (!icapIsolateLine(&parse_start, &blk_start, &blk_end)) { -+ debug(81, 3) ("icapOptParseReply: failure in isolating status line\n"); -+ return 0; -+ -+ } -+ /* now we might start real parsing */ -+ while (icapIsolateLine(&parse_start, &blk_start, &blk_end)) { -+ if (blk_end > head_end || blk_start > head_end || blk_start >= blk_end) { -+ debug(81, 3) ("icapOptParseReply: header limit exceeded. finished.\n"); -+ break; -+ } -+ icapOptParseEntry(s, blk_start, blk_end); -+ } -+ return 1; -+} -+ -+static void -+icapOptDataInit(IcapOptData * i) -+{ -+ i->buf = memAllocBuf(HTTP_REPLY_BUF_SZ, &i->size); -+ i->offset = 0; -+ i->headlen = 0; -+} -+ -+static void -+icapOptDataFree(IcapOptData * i) -+{ -+ if (i) { -+ memFreeBuf(i->size, i->buf); -+ memFree(i, MEM_ICAP_OPT_DATA); -+ } -+} -Index: src/icap_reqmod.c -=================================================================== -RCS file: src/icap_reqmod.c -diff -N src/icap_reqmod.c ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ src/icap_reqmod.c 6 Dec 2005 21:53:44 -0000 1.1.2.58 -@@ -0,0 +1,976 @@ -+ -+/* -+ * $Id$ -+ * -+ * DEBUG: section 81 Internet Content Adaptation Protocol (ICAP) Client -+ * AUTHOR: Geetha Manjunath, Hewlett Packard Company -+ * -+ * SQUID Web Proxy Cache http://www.squid-cache.org/ -+ * ---------------------------------------------------------- -+ * -+ * Squid is the result of efforts by numerous individuals from -+ * the Internet community; see the CONTRIBUTORS file for full -+ * details. Many organizations have provided support for Squid's -+ * development; see the SPONSORS file for full details. Squid is -+ * Copyrighted (C) 2001 by the Regents of the University of -+ * California; see the COPYRIGHT file for full details. Squid -+ * incorporates software developed and/or copyrighted by other -+ * sources; see the CREDITS file for full details. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. -+ * -+ */ -+ -+#include "squid.h" -+ -+#define ICAP_PROXY_KEEP_ALIVE 0 -+ -+/* -+ * These once-static functions are required to be global for ICAP -+ */ -+ -+PF clientReadRequest; -+PF connStateFree; -+int clientReadDefer(int fd, void *data); -+int clientCheckContentLength(request_t * r); -+void clientProcessRequest(clientHttpRequest *); -+int clientCachable(clientHttpRequest *); -+int clientHierarchical(clientHttpRequest *); -+void clientReadBody(request_t * request, char *buf, size_t size, -+ CBCB * callback, void *cbdata); -+static void icapReqModPassHttpBody(IcapStateData * icap, char *buf, size_t size, -+ CBCB * callback, void *cbdata); -+ -+static PF icapReqModReadHttpHdrs; -+static PF icapReqModReadHttpBody; -+static CWCB icapReqModSendBodyChunk; -+static CBCB icapReqModBodyHandler; -+static BODY_HANDLER icapReqModBodyReader; -+static STRCB icapReqModMemBufAppend; -+ -+#define EXPECTED_ICAP_HEADER_LEN 256 -+static const char *crlf = "\r\n"; -+ -+/* -+ * icapExpectedHttpReqHdrSize -+ * -+ * calculate the size of the HTTP headers that we expect -+ * to read from the ICAP server. -+ */ -+static int -+icapExpectedHttpReqHdrSize(IcapStateData * icap) -+{ -+ if (icap->enc.req_body > -1 && icap->enc.req_hdr > -1) -+ return (icap->enc.req_body - icap->enc.req_hdr); -+ if (icap->enc.null_body > -1) -+ return icap->enc.null_body; -+ fatal("icapExpectedHttpReqHdrSize: unexpected case"); -+ return 0; -+} -+ -+/* -+ * icapReqModCreateClientState -+ * -+ * Creates fake client_side data structures so we can use -+ * that module to read/parse the HTTP request that we read -+ * from the ICAP server. -+ */ -+static clientHttpRequest * -+icapReqModCreateClientState(IcapStateData * icap, request_t * request) -+{ -+ clientHttpRequest *http; -+ if (!cbdataValid(icap->reqmod.client_cookie)) { -+ debug(81, 3) ("Whups, client cookie invalid\n"); -+ icap->reqmod.client_fd = -1; -+ return NULL; -+ } -+ http = cbdataAlloc(clientHttpRequest); -+ /* -+ * use our own urlCanonicalClean here, because urlCanonicalClean -+ * may strip everything after a question-mark. As http->uri -+ * is used when doing a request to a parent proxy, we need the full -+ * url here. -+ */ -+ http->uri = xstrdup(urlCanonical(icap->request)); -+ http->log_uri = xstrndup(http->uri, MAX_URL); -+ http->range_iter.boundary = StringNull; -+ http->request = requestLink(request ? request : icap->request); -+ http->flags.did_icap_reqmod = 1; -+ http->start = icap->reqmod.start; -+#if 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->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->in.size = 0; -+ http->conn->in.buf = NULL; -+ http->conn->log_addr = icap->reqmod.log_addr; -+ http->conn->chr = http; -+ comm_add_close_handler(http->conn->fd, connStateFree, http->conn); -+#endif -+ http->icap_reqmod = NULL; -+ return http; -+} -+ -+/* -+ * icapReqModInterpretHttpRequest -+ * -+ * Interpret an HTTP request that we read from the ICAP server. -+ * Create some "fake" clientHttpRequest and ConnStateData structures -+ * so we can pass this new request off to the routines in -+ * client_side.c. -+ */ -+static void -+icapReqModInterpretHttpRequest(IcapStateData * icap, request_t * request) -+{ -+ clientHttpRequest *http = icapReqModCreateClientState(icap, request); -+ if (NULL == http) -+ return; -+ /* -+ * bits from clientReadRequest -+ */ -+ request->content_length = httpHeaderGetSize(&request->header, -+ HDR_CONTENT_LENGTH); -+ if (!urlCheckRequest(request) || -+ httpHeaderHas(&request->header, HDR_TRANSFER_ENCODING)) { -+ ErrorState *err; -+ err = errorCon(ERR_UNSUP_REQ, HTTP_NOT_IMPLEMENTED); -+ err->request = requestLink(request); -+ request->flags.proxy_keepalive = 0; -+ http->entry = -+ clientCreateStoreEntry(http, request->method, null_request_flags); -+ errorAppendEntry(http->entry, err); -+ return; -+ } -+ if (!clientCheckContentLength(request)) { -+ ErrorState *err; -+ err = errorCon(ERR_INVALID_REQ, HTTP_LENGTH_REQUIRED); -+ err->request = requestLink(request); -+ http->entry = -+ clientCreateStoreEntry(http, request->method, null_request_flags); -+ errorAppendEntry(http->entry, err); -+ return; -+ } -+ /* Do we expect a request-body? */ -+ if (request->content_length > 0) { -+ debug(81, 5) ("handing request bodies in ICAP REQMOD\n"); -+ if (request->body_reader_data) -+ cbdataUnlock(request->body_reader_data); -+ request->body_reader = icapReqModBodyReader; -+ request->body_reader_data = icap; /* XXX cbdataLock? */ -+ cbdataLock(icap); /*Yes sure ..... */ -+ memBufDefInit(&icap->reqmod.http_entity.buf); -+ } -+ if (clientCachable(http)) -+ request->flags.cachable = 1; -+ if (clientHierarchical(http)) -+ request->flags.hierarchical = 1; -+ clientProcessRequest(http); -+} -+ -+/* -+ * icapReqModParseHttpError -+ * -+ * Handle an error when parsing the new HTTP request we read -+ * from the ICAP server. -+ */ -+static void -+icapReqModParseHttpError(IcapStateData * icap, const char *reason) -+{ -+ debug(81, 1) ("icapReqModParseHttpError: %s\n", reason); -+} -+ -+/* -+ * icapEntryError -+ * -+ * A wrapper for errorCon() and errorAppendEntry(). -+ */ -+static void -+icapEntryError(IcapStateData * icap, err_type et, http_status hs, int xerrno) -+{ -+ ErrorState *err; -+ clientHttpRequest *http = icapReqModCreateClientState(icap, NULL); -+ if (NULL == http) -+ return; -+ http->entry = clientCreateStoreEntry(http, -+ icap->request->method, null_request_flags); -+ err = errorCon(et, hs); -+ err->xerrno = xerrno; -+ err->request = requestLink(icap->request); -+ errorAppendEntry(http->entry, err); -+} -+ -+/* -+ * icapReqModParseHttpRequest -+ * -+ * Parse the HTTP request that we read from the ICAP server. -+ * Creates and fills in the request_t structure. -+ */ -+static void -+icapReqModParseHttpRequest(IcapStateData * icap) -+{ -+ char *mstr; -+ char *uri; -+ char *inbuf; -+ char *t; -+ char *token; -+ char *headers; -+ method_t method; -+ request_t *request; -+ http_version_t http_ver; -+ int reqlen = icap->reqmod.hdr_buf.size; -+ int hdrlen; -+ -+ /* -+ * Lazy, make a copy of the buf so I can chop it up with strtok() -+ */ -+ inbuf = xcalloc(reqlen + 1, 1); -+ memcpy(inbuf, icap->reqmod.hdr_buf.buf, reqlen); -+ -+ if ((mstr = strtok(inbuf, "\t ")) == NULL) { -+ debug(81, 1) ("icapReqModParseHttpRequest: Can't get request method\n"); -+ icapReqModParseHttpError(icap, "error:invalid-request-method"); -+ xfree(inbuf); -+ return; -+ } -+ method = urlParseMethod(mstr); -+ if (method == METHOD_NONE) { -+ debug(81, 1) ("icapReqModParseHttpRequest: Unsupported method '%s'\n", -+ mstr); -+ icapReqModParseHttpError(icap, "error:unsupported-request-method"); -+ xfree(inbuf); -+ return; -+ } -+ /* look for URL+HTTP/x.x */ -+ if ((uri = strtok(NULL, "\n")) == NULL) { -+ debug(81, 1) ("icapReqModParseHttpRequest: Missing URI\n"); -+ icapReqModParseHttpError(icap, "error:missing-url"); -+ xfree(inbuf); -+ return; -+ } -+ while (xisspace(*uri)) -+ uri++; -+ t = uri + strlen(uri); -+ assert(*t == '\0'); -+ token = NULL; -+ while (t > uri) { -+ t--; -+ if (xisspace(*t) && !strncmp(t + 1, "HTTP/", 5)) { -+ token = t + 1; -+ break; -+ } -+ } -+ while (t > uri && xisspace(*t)) -+ *(t--) = '\0'; -+ debug(81, 5) ("icapReqModParseHttpRequest: URI is '%s'\n", uri); -+ if (token == NULL) { -+ debug(81, 3) ("icapReqModParseHttpRequest: Missing HTTP identifier\n"); -+ icapReqModParseHttpError(icap, "error:missing-http-ident"); -+ xfree(inbuf); -+ return; -+ } -+ if (sscanf(token + 5, "%d.%d", &http_ver.major, &http_ver.minor) != 2) { -+ debug(81, 3) ("icapReqModParseHttpRequest: Invalid HTTP identifier.\n"); -+ icapReqModParseHttpError(icap, "error:invalid-http-ident"); -+ xfree(inbuf); -+ return; -+ } -+ debug(81, 6) ("icapReqModParseHttpRequest: Client HTTP version %d.%d.\n", -+ http_ver.major, http_ver.minor); -+ -+ headers = strtok(NULL, null_string); -+ hdrlen = inbuf + reqlen - headers; -+ -+ if ((request = urlParse(method, uri)) == NULL) { -+ debug(81, 3) ("Invalid URL: %s at %s:%d\n", uri, __FILE__, __LINE__); -+ icapEntryError(icap, ERR_INVALID_URL, HTTP_BAD_REQUEST, 0); -+ xfree(inbuf); -+ return; -+ } -+ /* compile headers */ -+ if (!httpHeaderParse(&request->header, headers, headers + hdrlen)) { -+ debug(81, 3) ("Failed to parse HTTP headers for: %s at %s:%d", -+ uri, __FILE__, __LINE__); -+ icapEntryError(icap, ERR_INVALID_REQ, HTTP_BAD_REQUEST, 0); -+ xfree(inbuf); -+ return; -+ } -+ debug(81, -+ 3) -+ ("icapReqModParseHttpRequest: successfully parsed the HTTP request\n"); -+ request->http_ver = http_ver; -+ request->client_addr = icap->request->client_addr; -+ request->my_addr = icap->request->my_addr; -+ request->my_port = icap->request->my_port; -+ request->class = icap->request->class; -+ if (icap->request->auth_user_request != NULL) { -+ /* Copy authentification info in new request */ -+ request->auth_user_request = icap->request->auth_user_request; -+ authenticateAuthUserRequestLock(request->auth_user_request); -+ } -+#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); -+ 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 (Config.icapcfg.send_client_ip || service->flags.need_x_client_ip) -+ memBufPrintf(&mb, "X-Client-IP: %s\r\n", client_addr); -+ if ((Config.icapcfg.send_auth_user -+ || service->flags.need_x_authenticated_user) -+ && (icap->request->auth_user_request != NULL)) -+ icapAddAuthUserHeader(&mb, icap->request->auth_user_request); -+ if (service->keep_alive) { -+ icap->flags.keep_alive = 1; -+ } else { -+ icap->flags.keep_alive = 0; -+ memBufAppend(&mb, "Connection: close\r\n", 19); -+ } -+ memBufAppend(&mb, crlf, 2); -+ memBufAppend(&mb, mb_hdr.buf, mb_hdr.size); -+ memBufClean(&mb_hdr); -+ -+ debug(81, 5) ("icapSendReqMod: FD %d writing {%s}\n", icap->icap_fd, -+ mb.buf); -+ comm_write_mbuf(icap_fd, mb, theCallback, icap); -+} -+ -+/* -+ * icapReqModStart -+ * -+ * Initiate an ICAP REQMOD transaction. Create and fill in IcapStateData -+ * structure and request a TCP connection to the server. -+ */ -+IcapStateData * -+icapReqModStart(icap_service *service, const char *uri, request_t * request, -+ int fd, struct timeval start, struct in_addr log_addr, void *cookie) -+{ -+ IcapStateData *icap = NULL; -+ -+ debug(81, 3) ("icapReqModStart: type=%d\n", (int) service->type); -+ -+ switch (service->type) { -+ case ICAP_SERVICE_REQMOD_PRECACHE: -+ break; -+ default: -+ fatalf("icapReqModStart: unsupported service type '%s'\n", -+ icap_service_type_str[service->type]); -+ break; -+ } -+ -+ if (service->unreachable) { -+ if (service->bypass) { -+ debug(81, -+ 5) ("icapReqModStart: BYPASS because service unreachable: %s\n", -+ service->uri); -+ return NULL; -+ } else { -+ debug(81, -+ 5) ("icapReqModStart: ERROR because service unreachable: %s\n", -+ service->uri); -+ return (IcapStateData *) - 1; -+ } -+ } -+ icap = icapAllocate(); -+ if (!icap) { -+ debug(81, 3) ("icapReqModStart: icapAllocate() failed\n"); -+ return NULL; -+ } -+ icap->current_service = service; -+ icap->preview_size = service->preview; -+ icap->reqmod.uri = uri; /* XXX should be xstrdup? */ -+ icap->reqmod.start = start; -+ icap->reqmod.log_addr = log_addr; -+ icap->request = requestLink(request); -+ icap->reqmod.hdr_state = 0; -+ icap->reqmod.client_fd = fd; -+ icap->reqmod.client_cookie = cookie; -+ cbdataLock(icap->reqmod.client_cookie); -+ -+ if (!icapConnect(icap, icapSendReqMod)) -+ return NULL; -+ -+ statCounter.icap.all.requests++; -+ debug(81, 3) ("icapReqModStart: returning %p\n", icap); -+ return icap; -+} -+ -+/* -+ * icapReqModSendBodyChunk -+ * -+ * A "comm_write" callback. This is called after comm_write() does -+ * its job to let us know how things went. If there are no errors, -+ * get another chunk of the body from client_side. -+ */ -+static void -+icapReqModSendBodyChunk(int fd, char *bufnotused, size_t size, int errflag, -+ void *data) -+{ -+ IcapStateData *icap = data; -+ debug(81, 3) ("icapReqModSendBodyChunk: FD %d wrote %d errflag %d.\n", -+ fd, (int) size, errflag); -+ if (errflag == COMM_ERR_CLOSING) -+ return; -+ if (errflag) { -+ icapEntryError(icap, ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR, -+ errno); -+ comm_close(fd); -+ return; -+ } -+ clientReadBody(icap->request, -+ memAllocate(MEM_8K_BUF), 8192, icapReqModBodyHandler, icap); -+} -+ -+/* -+ * icapReqModBodyHandler -+ * -+ * Called after Squid gets a chunk of the request entity from the -+ * client side. The body is chunkified and passed to comm_write. -+ * The comm_write callback depends on whether or not this is the -+ * last chunk. -+ */ -+static void -+icapReqModBodyHandler(char *buf, ssize_t size, void *data) -+{ -+ IcapStateData *icap = data; -+ MemBuf mb; -+ CWCB *theCallback = icapReqModSendBodyChunk; -+ if (size < 0) { -+ debug(81, 1) ("icapReqModBodyHandler: %s\n", xstrerror()); -+ memFree8K(buf); -+ return; -+ } -+ memBufDefInit(&mb); -+ debug(81, 3) ("icapReqModBodyHandler: writing chunk size %d\n", size); -+ memBufPrintf(&mb, "%x\r\n", size); -+ if (size) -+ memBufAppend(&mb, buf, size); -+ else -+ theCallback = icapSendReqModDone; -+ memBufAppend(&mb, crlf, 2); -+ memFree8K(buf); -+ comm_write_mbuf(icap->icap_fd, mb, theCallback, icap); -+} -+ -+/* -+ * icapReqModReadHttpBody -+ * -+ * The read handler for the client's HTTP connection when reading -+ * message bodies. Called by comm_select(). -+ */ -+static void -+icapReqModReadHttpBody(int fd, void *data) -+{ -+ IcapStateData *icap = data; -+ int len; -+ debug(81, 3) ("icapReqModReadHttpBody: FD %d called\n", fd); -+ len = memBufRead(fd, &icap->chunk_buf); -+ debug(81, 3) ("icapReqModReadHttpBody: read returns %d\n", len); -+ if (len < 0) { -+ debug(81, 3) ("icapReqModReadHttpBody: FD %d %s\n", fd, xstrerror()); -+ if (!ignoreErrno(errno)) -+ icap->flags.reqmod_http_entity_eof = 1; -+ } else if (0 == len) { -+ debug(81, 3) ("icapReqModReadHttpBody: FD %d EOF\n", fd); -+ icap->flags.reqmod_http_entity_eof = 1; -+ } else { -+ fd_bytes(fd, len, FD_READ); -+ kb_incr(&statCounter.icap.all.kbytes_in, len); -+ icap->reqmod.http_entity.bytes_read += -+ icapParseChunkedBody(icap, -+ icapReqModMemBufAppend, &icap->reqmod.http_entity.buf); -+ } -+ if (icap->reqmod.http_entity.bytes_read >= icap->request->content_length) -+ icap->flags.reqmod_http_entity_eof = 1; -+ -+ if (!icap->flags.reqmod_http_entity_eof) -+ commSetSelect(fd, COMM_SELECT_READ, icapReqModReadHttpBody, icap, 0); -+ /* -+ * Notify the other side if it is waiting for data from us -+ */ -+ debug(81, 3) ("%s:%d http_entity.callback=%p\n", __FILE__, __LINE__, -+ icap->reqmod.http_entity.callback); -+ debug(81, 3) ("%s:%d http_entity.buf.size=%d\n", __FILE__, __LINE__, -+ icap->reqmod.http_entity.buf.size); -+ if (icap->reqmod.http_entity.callback && icap->reqmod.http_entity.buf.size) { -+ icapReqModPassHttpBody(icap, -+ icap->reqmod.http_entity.callback_buf, -+ icap->reqmod.http_entity.callback_bufsize, -+ icap->reqmod.http_entity.callback, -+ icap->reqmod.http_entity.callback_data); -+ icap->reqmod.http_entity.callback = NULL; -+ cbdataUnlock(icap->reqmod.http_entity.callback_data); -+ -+ } -+} -+ -+/* -+ * icapReqModPassHttpBody -+ * -+ * Called from http.c after request headers have been sent. -+ * This function feeds the http.c module chunks of the request -+ * body that were stored in the http_entity.buf MemBuf. -+ */ -+static void -+icapReqModPassHttpBody(IcapStateData * icap, char *buf, size_t size, -+ CBCB * callback, void *cbdata) -+{ -+ debug(81, 3) ("icapReqModPassHttpBody: called\n"); -+ if (!buf) { -+ debug(81, 1) ("icapReqModPassHttpBody: FD %d called with %p, %d, %p (request aborted)\n", -+ icap->icap_fd, buf, (int) size, cbdata); -+ comm_close(icap->icap_fd); -+ return; -+ } -+ if (!cbdataValid(cbdata)) { -+ debug(81, -+ 1) -+ ("icapReqModPassHttpBody: FD %d callback data invalid, closing\n", -+ icap->icap_fd); -+ comm_close(icap->icap_fd); /*It is better to be sure that the connection will be closed..... */ -+ /*icapReqModKeepAliveOrClose(icap); */ -+ return; -+ } -+ debug(81, 3) ("icapReqModPassHttpBody: entity buf size = %d\n", -+ icap->reqmod.http_entity.buf.size); -+ if (icap->reqmod.http_entity.buf.size) { -+ int copy_sz = icap->reqmod.http_entity.buf.size; -+ if (copy_sz > size) -+ copy_sz = size; -+ xmemcpy(buf, icap->reqmod.http_entity.buf.buf, copy_sz); -+ /* XXX don't let Alex see this ugliness */ -+ xmemmove(icap->reqmod.http_entity.buf.buf, -+ icap->reqmod.http_entity.buf.buf + copy_sz, -+ icap->reqmod.http_entity.buf.size - copy_sz); -+ icap->reqmod.http_entity.buf.size -= copy_sz; -+ debug(81, 3) ("icapReqModPassHttpBody: giving %d bytes to other side\n", -+ copy_sz); -+ callback(buf, copy_sz, cbdata); -+ debug(81, 3) ("icapReqModPassHttpBody: entity buf size now = %d\n", -+ icap->reqmod.http_entity.buf.size); -+ return; -+ } -+ if (icap->flags.reqmod_http_entity_eof) { -+ debug(81, 3) ("icapReqModPassHttpBody: signalling EOF\n"); -+ callback(buf, 0, cbdata); -+ icapReqModKeepAliveOrClose(icap); -+ return; -+ } -+ /* -+ * We have no data for the other side at this point. Save all -+ * these values and use them when we do have data. -+ */ -+ assert(NULL == icap->reqmod.http_entity.callback); -+ icap->reqmod.http_entity.callback = callback; -+ icap->reqmod.http_entity.callback_data = cbdata; -+ icap->reqmod.http_entity.callback_buf = buf; -+ icap->reqmod.http_entity.callback_bufsize = size; -+ cbdataLock(icap->reqmod.http_entity.callback_data); -+} -+ -+/* -+ * Body reader handler for use with request->body_reader function -+ * Simple a wrapper for icapReqModPassHttpBody function -+ */ -+ -+static void -+icapReqModBodyReader(request_t * request, char *buf, size_t size, -+ CBCB * callback, void *cbdata) -+{ -+ IcapStateData *icap = request->body_reader_data; -+ icapReqModPassHttpBody(icap, buf, size, callback, cbdata); -+} -+ -+/* -+ * icapReqModMemBufAppend -+ * -+ * stupid wrapper to eliminate compiler warnings -+ */ -+static void -+icapReqModMemBufAppend(void *data, const char *buf, ssize_t size) -+{ -+ memBufAppend(data, buf, size); -+} -Index: src/icap_respmod.c -=================================================================== -RCS file: src/icap_respmod.c -diff -N src/icap_respmod.c ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ src/icap_respmod.c 23 Nov 2005 20:34:34 -0000 1.1.2.60 -@@ -0,0 +1,1039 @@ -+ -+/* -+ * $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 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 (Config.icapcfg.send_client_ip || service->flags.need_x_client_ip) { -+ memBufPrintf(mb, "X-Client-IP: %s\r\n", client_addr); -+ } -+ if ((Config.icapcfg.send_auth_user -+ || service->flags.need_x_authenticated_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 -+ if (service->flags.allow_204) -+ memBufPrintf(mb, "Allow: 204\r\n"); -+} -+ -+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); -+ } 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) { -+ /* No data sent yet. Start with headers */ -+ if ((icap->sc = buildRespModHeader(&mb, icap, buf, len, theEnd)) > 0) { -+ buf += icap->sc; -+ len -= icap->sc; -+ } -+ /* -+ * Then we do not have http responce headers. All data (previous and those in buf) -+ * now are exist to icap->respmod.req_hdr_copy. Lets get them back....... -+ */ -+ if (icap->sc < 0) { -+ memBufAppend(&icap->respmod.buffer, -+ icap->respmod.req_hdr_copy.buf, -+ icap->respmod.req_hdr_copy.size); -+ icap->sc = icap->respmod.req_hdr_copy.size; -+ icap->respmod.req_hdr_copy.size = 0; -+ buf = NULL; -+ len = 0; -+ } -+ } -+ if (0 == icap->sc) { -+ /* check again; bail if we're not ready to send ICAP/HTTP hdrs */ -+ debug(81, 5) ("icapSendRespMod: dont have full HTTP response hdrs\n"); -+ memBufClean(&mb); -+ return; -+ } -+#if ICAP_PREVIEW -+ if (preview_size < 0 || !Config.icapcfg.preview_enable) /* preview feature off */ -+ icap->flags.preview_done = 1; -+ -+ if (!icap->flags.preview_done) { -+ /* preview not yet sent */ -+ if (icap->sc > 0 && icap->respmod.buffer.size <= preview_size -+ && len > 0) { -+ /* Try to collect at least preview_size+1 bytes */ -+ /* By collecting one more byte than needed for preview we know best */ -+ /* whether we have to send the ieof chunk extension */ -+ size = icap->respmod.buffer.size + len; -+ if (size > preview_size + 1) -+ size = preview_size + 1; -+ size -= icap->respmod.buffer.size; -+ debug(81, -+ 3) -+ ("icapSendRespMod: FD %d: copy %d more bytes to preview buffer.\n", -+ icap->icap_fd, size); -+ memBufAppend(&icap->respmod.buffer, buf, size); -+ buf = ((char *) buf) + size; -+ len -= size; -+ } -+ if (icap->respmod.buffer.size > preview_size || theEnd) { -+ /* we got enough bytes for preview or this is the last call */ -+ /* add preview preview now */ -+ if (icap->respmod.buffer.size > 0) { -+ size = icap->respmod.buffer.size; -+ if (size > preview_size) -+ size = preview_size; -+ memBufPrintf(&mb, "%x\r\n", size); -+ memBufAppend(&mb, icap->respmod.buffer.buf, size); -+ memBufAppend(&mb, crlf, 2); -+ icap->sc += size; -+ } -+ if (icap->respmod.buffer.size <= preview_size) { -+ /* content length is less than preview size+1 */ -+ if (icap->respmod.res_body_sz) -+ memBufAppend(&mb, "0; ieof\r\n\r\n", 11); -+ memBufReset(&icap->respmod.buffer); /* will now be used for other data */ -+ } else { -+ char ch; -+ memBufAppend(&mb, "0\r\n\r\n", 5); -+ /* end of preview, wait for continue or 204 signal */ -+ /* copy the extra byte and all other data to the icap buffer */ -+ /* so that it can be handled next time */ -+ ch = icap->respmod.buffer.buf[preview_size]; -+ memBufReset(&icap->respmod.buffer); /* will now be used for other data */ -+ memBufAppend(&icap->respmod.buffer, &ch, 1); -+ debug(81, -+ 3) -+ ("icapSendRespMod: FD %d: sending preview and keeping %d bytes in internal buf.\n", -+ icap->icap_fd, len + 1); -+ if (len > 0) -+ memBufAppend(&icap->respmod.buffer, buf, len); -+ } -+ icap->flags.preview_done = 1; -+ icap->flags.wait_for_preview_reply = 1; -+ } -+ } else if (icap->flags.wait_for_preview_reply) { -+ /* received new data while waiting for preview response */ -+ /* add data to internal buffer and send later */ -+ debug(81, -+ 3) -+ ("icapSendRespMod: FD %d: add %d more bytes to internal buf while waiting for preview-response.\n", -+ icap->icap_fd, len); -+ if (len > 0) -+ memBufAppend(&icap->respmod.buffer, buf, len); -+ /* do not send any data now while waiting for preview response */ -+ /* but prepare for read more data on the HTTP connection */ -+ memBufClean(&mb); -+ return; -+ } else -+#endif -+ { -+ /* after preview completed and ICAP preview response received */ -+ /* there may still be some data in the buffer */ -+ if (icap->respmod.buffer.size > 0) { -+ memBufPrintf(&mb, "%x\r\n", icap->respmod.buffer.size); -+ memBufAppend(&mb, icap->respmod.buffer.buf, -+ icap->respmod.buffer.size); -+ memBufAppend(&mb, crlf, 2); -+ icap->sc += icap->respmod.buffer.size; -+ memBufReset(&icap->respmod.buffer); -+ } -+ if (len > 0) { -+ memBufPrintf(&mb, "%x\r\n", len); -+ memBufAppend(&mb, buf, len); -+ memBufAppend(&mb, crlf, 2); -+ icap->sc += len; -+ } -+ if (icap->flags.send_zero_chunk) { -+ /* send zero end chunk */ -+ icap->flags.send_zero_chunk = 0; -+ icap->flags.http_server_eof = 1; -+ memBufAppend(&mb, "0\r\n\r\n", 5); -+ } -+ /* wait for data coming from ICAP server as soon as we sent something */ -+ /* but of course only until we got the response header */ -+ if (!icap->flags.got_reply) -+ icap->flags.wait_for_reply = 1; -+ } -+ commSetTimeout(icap->icap_fd, -1, NULL, NULL); -+ -+ if (!mb.size) { -+ memBufClean(&mb); -+ return; -+ } -+ debug(81, 5) ("icapSendRespMod: FD %d writing {%s}\n", icap->icap_fd, -+ mb.buf); -+ icap->flags.write_pending = 1; -+ comm_write_mbuf(icap->icap_fd, mb, icapSendRespModDone, icap); -+} -+ -+static void -+icapRespModReadReply(int fd, void *data) -+{ -+ IcapStateData *icap = data; -+ int version_major, version_minor; -+ const char *str_status; -+ int x; -+ int status = 0; -+ int isIcap = 0; -+ int directResponse = 0; -+ ErrorState *err; -+ const char *start; -+ const char *end; -+ -+ debug(81, 5) ("icapRespModReadReply: FD %d data = %p\n", fd, data); -+ statCounter.syscalls.sock.reads++; -+ -+ x = icapReadHeader(fd, icap, &isIcap); -+ if (x < 0) { -+ /* Did not find a proper ICAP response */ -+ debug(81, 3) ("ICAP : Error path!\n"); -+ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR); -+ err->request = requestLink(icap->request); -+ err->xerrno = errno; -+ errorAppendEntry(icap->respmod.entry, err); -+ comm_close(fd); -+ return; -+ } -+ if (x == 0) { -+ /* -+ * Waiting for more headers. Schedule new read hander, but -+ * don't reset timeout. -+ */ -+ commSetSelect(fd, COMM_SELECT_READ, icapRespModReadReply, icap, 0); -+ return; -+ } -+ /* -+ * Parse the ICAP header -+ */ -+ assert(icap->icap_hdr.size); -+ debug(81, 3) ("Parse icap header : <%s>\n", icap->icap_hdr.buf); -+ if ((status = -+ icapParseStatusLine(icap->icap_hdr.buf, icap->icap_hdr.size, -+ &version_major, &version_minor, &str_status)) < 0) { -+ debug(81, 1) ("BAD ICAP status line <%s>\n", icap->icap_hdr.buf); -+ /* is this correct in case of ICAP protocol error? */ -+ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR); -+ err->request = requestLink(icap->request); -+ err->xerrno = errno; -+ errorAppendEntry(icap->respmod.entry, err); -+ comm_close(fd); -+ return; -+ }; -+ /* OK here we have responce. Lets stop filling the -+ * icap->respmod.resp_copy buffer .... -+ */ -+ icap->flags.copy_response = 0; -+ -+ icapSetKeepAlive(icap, icap->icap_hdr.buf); -+#if ICAP_PREVIEW -+ if (icap->flags.wait_for_preview_reply) { -+ if (100 == status) { -+ debug(81, 5) ("icapRespModReadReply: 100 Continue received\n"); -+ icap->flags.wait_for_preview_reply = 0; -+ /* if http_server_eof -+ * call again icapSendRespMod to handle data that -+ * was received while waiting for this ICAP response -+ * else let http to call icapSendRespMod when new data arrived -+ */ -+ if (icap->flags.http_server_eof) -+ icapSendRespMod(icap, NULL, 0, 0); -+ /* -+ * reset the header to send the rest of the preview -+ */ -+ if (!memBufIsNull(&icap->icap_hdr)) -+ memBufReset(&icap->icap_hdr); -+ -+ /*We do n't need it any more ....... */ -+ if (!memBufIsNull(&icap->respmod.resp_copy)) -+ memBufClean(&icap->respmod.resp_copy); -+ -+ return; -+ } -+ if (204 == status) { -+ debug(81, -+ 5) ("icapRespModReadReply: 204 No modification received\n"); -+ icap->flags.wait_for_preview_reply = 0; -+ } -+ } -+#endif /*ICAP_PREVIEW */ -+ -+#if SUPPORT_ICAP_204 || ICAP_PREVIEW -+ if (204 == status) { -+ debug(81, 3) ("got 204 status from ICAP server\n"); -+ 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) -+ comm_close(fd); -+ /* -+ * XXX ideally want to clean icap->respmod.resp_copy here -+ * XXX ideally want to "close" ICAP server connection here -+ * OK do it.... -+ */ -+ if (!memBufIsNull(&icap->respmod.resp_copy)) -+ memBufClean(&icap->respmod.resp_copy); -+ return; -+ } -+#endif -+ if (200 != status && 201 != status) { -+ debug(81, 1) ("Unsupported status '%d' from ICAP server\n", status); -+ /* Did not find a proper ICAP response */ -+ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR); -+ err->request = requestLink(icap->request); -+ err->xerrno = errno; -+ errorAppendEntry(icap->respmod.entry, err); -+ comm_close(fd); -+ return; -+ } -+ if (icapFindHeader(icap->icap_hdr.buf, "Encapsulated:", &start, &end)) { -+ icapParseEncapsulated(icap, start, end); -+ } else { -+ debug(81, -+ 1) -+ ("WARNING: icapRespModReadReply() did not find 'Encapsulated' header\n"); -+ } -+ if (icap->enc.res_hdr > -1) -+ directResponse = 1; -+ else if (icap->enc.res_body > -1) -+ directResponse = 1; -+ else -+ directResponse = 0; -+ -+ /* -+ * "directResponse" is the normal case here. If we don't have -+ * a response header or body, it is an error. -+ */ -+ if (!directResponse) { -+ /* Did not find a proper ICAP response */ -+ debug(81, 3) ("ICAP : Error path!\n"); -+ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR); -+ err->request = requestLink(icap->request); -+ err->xerrno = errno; -+ errorAppendEntry(icap->respmod.entry, err); -+ comm_close(fd); -+ return; -+ } -+ /* got the reply, no need to come here again */ -+ icap->flags.wait_for_reply = 0; -+ icap->flags.got_reply = 1; -+ /* Next, gobble any data before the HTTP response starts */ -+ if (icap->enc.res_hdr > -1) -+ icap->bytes_to_gobble = icap->enc.res_hdr; -+ commSetSelect(fd, COMM_SELECT_READ, icapRespModGobble, icap, 0); -+} -+ -+ -+/* -+ * Gobble up (read) some bytes until we get to the start of the body -+ */ -+static void -+icapRespModGobble(int fd, void *data) -+{ -+ IcapStateData *icap = data; -+ int len; -+ LOCAL_ARRAY(char, junk, SQUID_TCP_SO_RCVBUF); -+ debug(81, 3) ("icapRespModGobble: FD %d gobbling %d bytes\n", fd, -+ icap->bytes_to_gobble); -+ len = FD_READ_METHOD(fd, junk, icap->bytes_to_gobble); -+ debug(81, 3) ("icapRespModGobble: gobbled %d bytes\n", len); -+ if (len < 0) { -+ /* XXX error */ -+ abort(); -+ } -+ icap->bytes_to_gobble -= len; -+ if (icap->bytes_to_gobble) -+ commSetSelect(fd, COMM_SELECT_READ, icapRespModGobble, icap, 0); -+ else -+ icapReadReply(fd, icap); -+} -+ -+ -+static void -+icapSendRespModDone(int fd, char *bufnotused, size_t size, int errflag, -+ void *data) -+{ -+ IcapStateData *icap = data; -+ ErrorState *err; -+ -+ icap->flags.write_pending = 0; -+ debug(81, 5) ("icapSendRespModDone: FD %d: size %d: errflag %d.\n", -+ fd, size, errflag); -+ if (size > 0) { -+ fd_bytes(fd, size, FD_WRITE); -+ kb_incr(&statCounter.icap.all.kbytes_out, size); -+ } -+ if (errflag == COMM_ERR_CLOSING) -+ return; -+ if (errflag) { -+ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR); -+ err->xerrno = errno; -+ if (cbdataValid(icap)) -+ err->request = requestLink(icap->request); -+ storeEntryReset(icap->respmod.entry); -+ errorAppendEntry(icap->respmod.entry, err); -+ comm_close(fd); -+ return; -+ } -+ if (EBIT_TEST(icap->respmod.entry->flags, ENTRY_ABORTED)) { -+ debug(81, 3) ("icapSendRespModDone: Entry Aborded\n"); -+ comm_close(fd); -+ return; -+ } -+ if (icap->flags.send_zero_chunk) { -+ debug(81, -+ 3) ("icapSendRespModDone: I'm supposed to send zero chunk now\n"); -+ icap->flags.send_zero_chunk = 0; -+ icapSendRespMod(icap, NULL, 0, 1); -+ return; -+ } -+ if (icap->flags.wait_for_preview_reply || icap->flags.wait_for_reply) { -+ /* Schedule reading the ICAP response */ -+ debug(81, -+ 3) -+ ("icapSendRespModDone: FD %d: commSetSelect on read icapRespModReadReply.\n", -+ fd); -+ commSetSelect(fd, COMM_SELECT_READ, icapRespModReadReply, icap, 0); -+#if 1 -+ commSetTimeout(fd, Config.Timeout.read, icapReadTimeout, icap); -+#else -+ if (icap->flags.wait_for_preview_reply || icap->flags.http_server_eof) { -+ /* -+ * Set the read timeout only after all data has been sent -+ * or we are waiting for a preview response -+ * If the ICAP server does not return any data till all data -+ * has been sent, we are likely to hit the timeout for large -+ * HTTP bodies -+ */ -+ commSetTimeout(fd, Config.Timeout.read, icapReadTimeout, icap); -+ } -+#endif -+ } -+} -+ -+void -+icapConnectOver(int fd, int status, void *data) -+{ -+ ErrorState *err; -+ IcapStateData *icap = data; -+ debug(81, 3) ("icapConnectOver: FD %d, status=%d\n", fd, status); -+ icap->flags.connect_pending = 0; -+ if (status < 0) { -+ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR); -+ err->xerrno = errno; -+ err->request = requestLink(icap->request); -+ errorAppendEntry(icap->respmod.entry, err); -+ comm_close(fd); -+ debug(81, 3) ("icapConnectOver: status < 0, unreachable=1\n"); -+ icapOptSetUnreachable(icap->current_service); -+ return; -+ } -+ fd_table[fd].pconn.uses++; -+ fd_table[fd].pconn.type = 2; -+ commSetSelect(fd, COMM_SELECT_READ, icapRespModReadReply, icap, 0); -+} -+ -+ -+ -+IcapStateData * -+icapRespModStart(icap_service_t type, request_t * request, StoreEntry * entry, -+ http_state_flags http_flags) -+{ -+ IcapStateData *icap = NULL; -+ CNCB *theCallback = NULL; -+ icap_service *service = NULL; -+ -+ debug(81, 3) ("icapRespModStart: type=%d\n", (int) type); -+ assert(type >= 0 && type < ICAP_SERVICE_MAX); -+ -+ service = icapService(type, request); -+ if (!service) { -+ debug(81, 3) ("icapRespModStart: no service found\n"); -+ return NULL; /* no service found */ -+ } -+ if (service->unreachable) { -+ if (service->bypass) { -+ debug(81, -+ 5) -+ ("icapRespModStart: BYPASS because service unreachable: %s\n", -+ service->uri); -+ return NULL; -+ } else { -+ debug(81, -+ 5) -+ ("icapRespModStart: ERROR because service unreachable: %s\n", -+ service->uri); -+ return (IcapStateData *) - 1; -+ } -+ } -+ switch (type) { -+ /* TODO: When we support more than ICAP_SERVICE_RESPMOD_PRECACHE, we needs to change -+ * this switch, because callbacks isn't keep */ -+ case ICAP_SERVICE_RESPMOD_PRECACHE: -+ theCallback = icapConnectOver; -+ break; -+ default: -+ fatalf("icapRespModStart: unsupported service type '%s'\n", -+ icap_service_type_str[type]); -+ break; -+ } -+ -+ icap = icapAllocate(); -+ if (!icap) { -+ debug(81, 3) ("icapRespModStart: icapAllocate() failed\n"); -+ return NULL; -+ } -+ icap->request = requestLink(request); -+ icap->respmod.entry = entry; -+ if (entry) -+ storeLockObject(entry); -+ icap->http_flags = http_flags; -+ memBufDefInit(&icap->respmod.buffer); -+ memBufDefInit(&icap->chunk_buf); -+ -+ icap->current_service = service; -+ icap->preview_size = service->preview; -+ -+ /* -+ * Don't create socket to the icap server now, but only for the first -+ * packet receive from the http server. This will resolve all timeout -+ * between the web server and icap server. -+ */ -+ debug(81, 3) ("icapRespModStart: setting connect_requested to 0\n"); -+ icap->flags.connect_requested = 0; -+ -+ /* -+ * make a copy the HTTP response that we send to the ICAP server in -+ * case it turns out to be a 204 -+ */ -+#ifdef SUPPORT_ICAP_204 -+ icap->flags.copy_response = 1; -+#elif ICAP_PREVIEW -+ if (preview_size < 0 || !Config.icapcfg.preview_enable) -+ icap->flags.copy_response = 0; -+ else -+ icap->flags.copy_response = 1; -+#else -+ icap->flags.copy_response = 0; -+#endif -+ -+ statCounter.icap.all.requests++; -+ debug(81, 3) ("icapRespModStart: returning %p\n", icap); -+ return icap; -+} -+ -+static int -+icapHttpReplyHdrState(IcapStateData * icap) -+{ -+ assert(icap); -+ if (NULL == icap->httpState) -+ return 0; -+ return icap->httpState->reply_hdr_state; -+} -+ -+static void -+icapProcessHttpReplyHeader(IcapStateData * icap, const char *buf, int size) -+{ -+ if (NULL == icap->httpState) { -+ icap->httpState = cbdataAlloc(HttpStateData); -+ icap->httpState->request = requestLink(icap->request); -+ icap->httpState->orig_request = requestLink(icap->request); -+ icap->httpState->entry = icap->respmod.entry; -+ storeLockObject(icap->httpState->entry); /* lock it */ -+ } -+ httpProcessReplyHeader(icap->httpState, buf, size); -+ if (2 == icap->httpState->reply_hdr_state) -+ EBIT_CLR(icap->httpState->entry->flags, ENTRY_FWD_HDR_WAIT); -+} -+ -+/* -+ * icapRespModKeepAliveOrClose -+ * -+ * Called when we are done reading from the ICAP server. -+ * Either close the connection or keep it open for a future -+ * transaction. -+ */ -+static void -+icapRespModKeepAliveOrClose(IcapStateData * icap) -+{ -+ int fd = icap->icap_fd; -+ if (fd < 0) -+ return; -+ if (!icap->flags.keep_alive) { -+ debug(81, 3) ("%s:%d keep_alive not set, closing\n", __FILE__, -+ __LINE__); -+ comm_close(fd); -+ 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); -+ pconnPush(fd, icap->current_service->hostname, icap->current_service->port); -+ icap->icap_fd = -1; -+ icapStateFree(-1, icap); -+} -+ -+ -+ -+/* -+ * copied from httpPconnTransferDone -+ * -+ */ -+static int -+icapPconnTransferDone(int fd, IcapStateData * icap) -+{ -+ debug(81, 3) ("icapPconnTransferDone: FD %d\n", fd); -+ /* -+ * Be careful with 204 responses. Normally we are done when we -+ * see the zero-end chunk, but that won't happen for 204s, so we -+ * use an EOF indicator on the HTTP side instead. -+ */ -+ if (icap->flags.no_content && icap->flags.http_server_eof) { -+ debug(81, 5) ("icapPconnTransferDone: no content, ret 1\n"); -+ return 1; -+ } -+ if (icapHttpReplyHdrState(icap) != 2) { -+ debug(81, -+ 5) ("icapPconnTransferDone: didn't see end of HTTP hdrs, ret 0\n"); -+ return 0; -+ } -+ if (icap->enc.null_body > -1) { -+ debug(81, 5) ("icapPconnTransferDone: no message body, ret 1\n"); -+ return 1; -+ } -+ if (icap->chunk_size == -2) { //AI: was != -2 ; and change content with bottom -+ /* zero end chunk reached */ -+ debug(81, 5) ("icapPconnTransferDone: got zero end chunk\n"); -+ return 1; -+ } -+ debug(81, 5) ("icapPconnTransferDone: didnt get zero end chunk yet\n"); //AI: change with second top condition -+ -+ return 0; -+} -+ -+static int -+icapExpectedHttpReplyHdrSize(IcapStateData * icap) -+{ -+ if (icap->enc.res_body > -1 && icap->enc.res_hdr > -1) -+ return (icap->enc.res_body - icap->enc.res_hdr); -+ if (icap->enc.null_body > -1 && icap->enc.res_hdr > -1) -+ return icap->enc.null_body - icap->enc.res_hdr; -+ /*The case we did not get res_hdr ..... */ -+ if (icap->enc.res_body > -1) -+ return icap->enc.res_body; -+ if (icap->enc.null_body > -1) -+ return icap->enc.null_body; -+ return -1; -+} -+ -+/* -+ * copied from httpReadReply() -+ * -+ * by the time this is called, the ICAP headers have already -+ * been read. -+ */ -+void -+icapReadReply(int fd, void *data) -+{ -+ IcapStateData *icap = data; -+ StoreEntry *entry = icap->respmod.entry; -+ const request_t *request = icap->request; -+ int len; -+ debug(81, 5) ("icapReadReply: FD %d: icap %p.\n", fd, data); -+ if (icap->flags.no_content && !icap->flags.http_server_eof) { //AI -+ -+ return; -+ } -+ if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) { -+ comm_close(fd); -+ return; -+ } -+ errno = 0; -+ statCounter.syscalls.sock.reads++; -+ len = memBufRead(fd, &icap->chunk_buf); -+ debug(81, 5) ("icapReadReply: FD %d: len %d.\n", fd, len); -+ if (len > 0) { -+ fd_bytes(fd, len, FD_READ); -+ kb_incr(&statCounter.icap.all.kbytes_in, len); -+ commSetTimeout(fd, Config.Timeout.read, icapReadTimeout, icap); -+ if (icap->chunk_buf.size < icap->chunk_buf.capacity) { -+ *(icap->chunk_buf.buf + icap->chunk_buf.size) = '\0'; -+ debug(81, 9) ("{%s}\n", icap->chunk_buf.buf); -+ } -+ } -+ if (len <= 0) { -+ debug(81, 2) ("icapReadReply: FD %d: read failure: %s.\n", -+ fd, xstrerror()); -+ if (ignoreErrno(errno)) { -+ debug(81, 2) ("icapReadReply: FD %d: ignored errno\n", fd); -+ commSetSelect(fd, COMM_SELECT_READ, icapReadReply, icap, 0); -+ } else if (entry->mem_obj->inmem_hi == 0) { -+ ErrorState *err; -+ debug(81, 2) ("icapReadReply: FD %d: generating error page\n", fd); -+ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR); -+ err->request = requestLink((request_t *) request); -+ err->xerrno = errno; -+ errorAppendEntry(entry, err); -+ comm_close(fd); -+ } else { -+ debug(81, 2) ("icapReadReply: FD %d: just calling comm_close()\n", -+ fd); -+ comm_close(fd); -+ } -+ return; -+ } -+ if (icapReadReply2(icap) < 0) -+ comm_close(fd); -+} -+ -+static int -+icapReadReply2(IcapStateData * icap) -+{ -+ StoreEntry *entry = icap->respmod.entry; -+ const request_t *request = icap->request; -+ debug(81, 3) ("icapReadReply2\n"); -+ if (icap->chunk_buf.size == 0 && entry->mem_obj->inmem_hi == 0) { -+ ErrorState *err; -+ err = errorCon(ERR_ZERO_SIZE_OBJECT, HTTP_SERVICE_UNAVAILABLE); -+ err->xerrno = errno; -+ err->request = requestLink((request_t *) request); -+ errorAppendEntry(entry, err); -+ icap->flags.http_server_eof = 1; -+ return -1; -+ } -+ if (icap->chunk_buf.size == 0) { -+ /* Retrieval done. */ -+ if (icapHttpReplyHdrState(icap) < 2) -+ icapProcessHttpReplyHeader(icap, icap->chunk_buf.buf, -+ icap->chunk_buf.size); -+ icap->flags.http_server_eof = 1; -+ icapReadReply3(icap); -+ return 0; -+ } -+ if (icapHttpReplyHdrState(icap) == 0) { -+ int expect = icapExpectedHttpReplyHdrSize(icap); -+ int so_far = icap->http_header_bytes_read_so_far; -+ int needed = expect - so_far; -+ debug(81, 3) ("expect=%d\n", expect); -+ debug(81, 3) ("so_far=%d\n", so_far); -+ debug(81, 3) ("needed=%d\n", needed); -+ assert(needed < 0 || needed >= 0); -+ if (0 > expect) { -+ icapProcessHttpReplyHeader(icap, -+ icap->chunk_buf.buf, icap->chunk_buf.size); -+ } else if (0 == expect) { -+ /* -+ * this icap reply doesn't give us new HTTP headers -+ * so we must copy them from our copy -+ */ -+ debug(81, 1) ("WARNING: untested code at %s:%d\n", __FILE__, -+ __LINE__); -+ if (icap->respmod.req_hdr_copy.size) { /*For HTTP 0.9 we do not have headers */ -+ storeAppend(entry, -+ icap->respmod.req_hdr_copy.buf, -+ icap->respmod.req_hdr_copy.size); -+ } -+ icapProcessHttpReplyHeader(icap, icap->chunk_buf.buf, -+ icap->chunk_buf.size); -+ assert(icapHttpReplyHdrState(icap) == 2); -+ icap->chunk_size = 0; /*we are ready to read chunks of data now.... */ -+ } else if (needed) { -+ icapProcessHttpReplyHeader(icap, -+ icap->chunk_buf.buf, icap->chunk_buf.size); -+ if (icap->chunk_buf.size >= needed) { -+ storeAppend(entry, icap->chunk_buf.buf, needed); -+ so_far += needed; -+ xmemmove(icap->chunk_buf.buf, -+ icap->chunk_buf.buf + needed, -+ icap->chunk_buf.size - needed); -+ icap->chunk_buf.size -= needed; -+ assert(icapHttpReplyHdrState(icap) == 2); -+ icap->chunk_size = 0; -+ } else { -+ /* -+ * We don't have the full HTTP reply headers yet, so keep -+ * the partial reply buffered in 'chunk_buf' and wait -+ * for more. -+ */ -+ debug(81, 3) ("We don't have full Http headers.Schedule a new read\n"); -+ commSetSelect(icap->icap_fd, COMM_SELECT_READ, icapReadReply, icap, 0); -+ } -+ } -+ icap->http_header_bytes_read_so_far = so_far; -+ } -+ debug(81, 3) ("%s:%d: icap->chunk_buf.size=%d\n", __FILE__, __LINE__, -+ (int) icap->chunk_buf.size); -+ debug(81, 3) ("%s:%d: flags.no_content=%d\n", __FILE__, __LINE__, -+ icap->flags.no_content); -+ if (icap->flags.no_content) { -+ /* data from http.c is not chunked */ -+ if (!EBIT_TEST(entry->flags, ENTRY_ABORTED)) { -+ debug(81, 3) ("copying %d bytes from chunk_buf to entry\n", -+ icap->chunk_buf.size); -+ storeAppend(entry, icap->chunk_buf.buf, icap->chunk_buf.size); -+ icap->chunk_buf.size = 0; -+ } -+ } else if (2 == icapHttpReplyHdrState(icap)) { -+ if (icap->chunk_buf.size) -+ icapParseChunkedBody(icap, (STRCB *) storeAppend, entry); -+ } -+ icapReadReply3(icap); -+ return 0; -+} -+ -+static void -+icapReadReply3(IcapStateData * icap) -+{ -+ StoreEntry *entry = icap->respmod.entry; -+ int fd = icap->icap_fd; -+ debug(81, 3) ("icapReadReply3\n"); -+ if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) { -+ debug(81, 3) ("icapReadReply3: Entry Aborded\n"); -+ comm_close(fd); -+ } else if (icapPconnTransferDone(fd, icap)) { -+ storeComplete(entry); -+ icapRespModKeepAliveOrClose(icap); -+ } else if (!icap->flags.no_content) { -+ /* Wait for EOF condition */ -+ commSetSelect(fd, COMM_SELECT_READ, icapReadReply, icap, 0); -+ debug(81, -+ 3) -+ ("icapReadReply3: Going to read mode data throught icapReadReply\n"); -+ } else { -+ debug(81, 3) ("icapReadReply3: Nothing\n"); -+ } -+} -Index: src/main.c -=================================================================== -RCS file: /cvsroot/squid/squid/src/main.c,v -retrieving revision 1.28.6.25 -retrieving revision 1.28.6.8.2.11 -diff -p -u -b -r1.28.6.25 -r1.28.6.8.2.11 ---- src/main.c 28 Jun 2005 02:16:51 -0000 1.28.6.25 -+++ src/main.c 12 Sep 2005 18:34:41 -0000 1.28.6.8.2.11 -@@ -350,6 +350,9 @@ mainReconfigure(void) - #else - idnsShutdown(); - #endif -+#ifdef HS_FEAT_ICAP -+ icapClose(); -+#endif - redirectShutdown(); - authenticateShutdown(); - externalAclShutdown(); -@@ -378,6 +381,9 @@ mainReconfigure(void) - idnsInit(); - #endif - redirectInit(); -+#ifdef HS_FEAT_ICAP -+ icapInit(); -+#endif - authenticateInit(&Config.authConfig); - externalAclInit(); - #if USE_WCCP -@@ -507,6 +513,9 @@ mainInitialize(void) - idnsInit(); - #endif - redirectInit(); -+#ifdef HS_FEAT_ICAP -+ icapInit(); -+#endif - authenticateInit(&Config.authConfig); - externalAclInit(); - useragentOpenLog(); -Index: src/mem.c -=================================================================== -RCS file: /cvsroot/squid/squid/src/mem.c,v -retrieving revision 1.13 -retrieving revision 1.13.28.2 -diff -p -u -b -r1.13 -r1.13.28.2 ---- src/mem.c 7 Sep 2001 23:55:49 -0000 1.13 -+++ src/mem.c 27 Jun 2003 01:15:18 -0000 1.13.28.2 -@@ -243,6 +243,13 @@ memInit(void) - memDataInit(MEM_CLIENT_REQ_BUF, "clientRequestBuffer", CLIENT_REQ_BUF_SZ, 0); - memDataInit(MEM_SWAP_LOG_DATA, "storeSwapLogData", sizeof(storeSwapLogData), 0); - -+#ifdef HS_FEAT_ICAP -+ memDataInit(MEM_ICAP_OPT_DATA, "IcapOptData", sizeof(IcapOptData), 0); -+ memDataInit(MEM_ICAP_SERVICE_LIST, "icap_service_list", sizeof(icap_service_list), 0); -+ memDataInit(MEM_ICAP_CLASS, "icap_class", sizeof(icap_class), 0); -+ memDataInit(MEM_ICAP_ACCESS, "icap_access", sizeof(icap_access), 0); -+#endif -+ - /* init string pools */ - for (i = 0; i < mem_str_pool_count; i++) { - StrPools[i].pool = memPoolCreate(StrPoolsAttrs[i].name, StrPoolsAttrs[i].obj_size); -Index: src/mk-string-arrays.pl -=================================================================== -RCS file: /cvsroot/squid/squid/src/mk-string-arrays.pl,v -retrieving revision 1.2 -retrieving revision 1.2.140.1 -diff -p -u -b -r1.2 -r1.2.140.1 ---- src/mk-string-arrays.pl 23 Oct 2000 15:04:21 -0000 1.2 -+++ src/mk-string-arrays.pl 4 Apr 2003 16:55:44 -0000 1.2.140.1 -@@ -16,6 +16,7 @@ $pat{'err_type'} = "err_type_str"; - $pat{'icp_opcode'} = "icp_opcode_str"; - $pat{'swap_log_op'} = "swap_log_op_str"; - $pat{'lookup_t'} = "lookup_t_str"; -+$pat{'icap_service_t'} = "icap_service_type_str"; - - $state = 0; # start state - while (<>) { -Index: src/pconn.c -=================================================================== -RCS file: /cvsroot/squid/squid/src/pconn.c,v -retrieving revision 1.6.38.2 -retrieving revision 1.6.60.2 -diff -p -u -b -r1.6.38.2 -r1.6.60.2 ---- src/pconn.c 16 Dec 2003 03:13:59 -0000 1.6.38.2 -+++ src/pconn.c 23 Nov 2005 20:33:07 -0000 1.6.60.2 -@@ -46,6 +46,9 @@ struct _pconn { - #define PCONN_HIST_SZ (1<<16) - int client_pconn_hist[PCONN_HIST_SZ]; - int server_pconn_hist[PCONN_HIST_SZ]; -+#ifdef HS_FEAT_ICAP -+int icap_server_pconn_hist[PCONN_HIST_SZ]; -+#endif - - static PF pconnRead; - static PF pconnTimeout; -@@ -159,6 +162,20 @@ pconnHistDump(StoreEntry * e) - continue; - storeAppendPrintf(e, "\t%4d %9d\n", i, server_pconn_hist[i]); - } -+#ifdef HS_FEAT_ICAP -+ storeAppendPrintf(e, -+ "\n" -+ "ICAP-server persistent connection counts:\n" -+ "\n" -+ "\treq/\n" -+ "\tconn count\n" -+ "\t---- ---------\n"); -+ for (i = 0; i < PCONN_HIST_SZ; i++) { -+ if (icap_server_pconn_hist[i] == 0) -+ continue; -+ storeAppendPrintf(e, "\t%4d %9d\n", i, icap_server_pconn_hist[i]); -+ } -+#endif - } - - /* ========== PUBLIC FUNCTIONS ============================================ */ -@@ -173,6 +190,9 @@ pconnInit(void) - for (i = 0; i < PCONN_HIST_SZ; i++) { - client_pconn_hist[i] = 0; - server_pconn_hist[i] = 0; -+#ifdef HS_FEAT_ICAP -+ icap_server_pconn_hist[i] = 0; -+#endif - } - pconn_data_pool = memPoolCreate("pconn_data", sizeof(struct _pconn)); - pconn_fds_pool = memPoolCreate("pconn_fds", PCONN_FDS_SZ * sizeof(int)); -@@ -248,11 +268,15 @@ pconnHistCount(int what, int i) - { - if (i >= PCONN_HIST_SZ) - i = PCONN_HIST_SZ - 1; -- /* what == 0 for client, 1 for server */ -+ /* what == 0 for client, 1 for server, 2 for ICAP server */ - if (what == 0) - client_pconn_hist[i]++; - else if (what == 1) - server_pconn_hist[i]++; -+#ifdef HS_FEAT_ICAP -+ else if (what == 2) -+ icap_server_pconn_hist[i]++; -+#endif - else - assert(0); - } -Index: src/protos.h -=================================================================== -RCS file: /cvsroot/squid/squid/src/protos.h,v -retrieving revision 1.41.6.33 -retrieving revision 1.41.6.13.2.37 -diff -p -u -b -r1.41.6.33 -r1.41.6.13.2.37 ---- src/protos.h 16 Sep 2005 02:13:25 -0000 1.41.6.33 -+++ src/protos.h 6 Dec 2005 21:53:44 -0000 1.41.6.13.2.37 -@@ -292,6 +292,8 @@ extern void whoisStart(FwdState *); - /* http.c */ - extern int httpCachable(method_t); - extern void httpStart(FwdState *); -+extern void httpParseReplyHeaders(const char *, http_reply *); -+extern void httpProcessReplyHeader(HttpStateData *, const char *, int); - extern int httpBuildRequestPrefix(request_t * request, - request_t * orig_request, - StoreEntry * entry, -@@ -614,6 +616,7 @@ extern void memBufVPrintf(MemBuf * mb, c - extern FREE *memBufFreeFunc(MemBuf * mb); - /* puts report on MemBuf _module_ usage into mb */ - extern void memBufReport(MemBuf * mb); -+extern int memBufRead(int fd, MemBuf * mb); - - extern char *mime_get_header(const char *mime, const char *header); - extern char *mime_get_header_field(const char *mime, const char *name, const char *prefix); -@@ -1341,4 +1344,49 @@ extern void externalAclShutdown(void); - extern int externalAclRequiresAuth(void *acl_data); - extern char *strtokFile(void); - -+#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); -+/* for debugging purposes only */ -+void dump_icap_config(IcapConfig * cfg); -+#endif -+ - #endif /* SQUID_PROTOS_H */ -Index: src/squid.h -=================================================================== -RCS file: /cvsroot/squid/squid/src/squid.h,v -retrieving revision 1.13.6.8 -retrieving revision 1.13.6.6.2.11 -diff -p -u -b -r1.13.6.8 -r1.13.6.6.2.11 ---- src/squid.h 26 Mar 2005 03:15:58 -0000 1.13.6.8 -+++ src/squid.h 15 May 2005 20:10:33 -0000 1.13.6.6.2.11 -@@ -38,6 +38,14 @@ - #include "config.h" - - /* -+ * experimental defines for ICAP -+ */ -+#ifdef HS_FEAT_ICAP -+#define ICAP_PREVIEW 1 -+#define SUPPORT_ICAP_204 0 -+#endif -+ -+/* - * On some systems, FD_SETSIZE is set to something lower than the - * actual number of files which can be opened. IRIX is one case, - * NetBSD is another. So here we increase FD_SETSIZE to our -Index: src/stat.c -=================================================================== -RCS file: /cvsroot/squid/squid/src/stat.c,v -retrieving revision 1.13.6.14 -retrieving revision 1.13.6.7.2.7 -diff -p -u -b -r1.13.6.14 -r1.13.6.7.2.7 ---- src/stat.c 30 Mar 2005 02:17:46 -0000 1.13.6.14 -+++ src/stat.c 23 Nov 2005 20:33:07 -0000 1.13.6.7.2.7 -@@ -775,6 +775,17 @@ statAvgDump(StoreEntry * sentry, int min - storeAppendPrintf(sentry, "server.other.kbytes_out = %f/sec\n", - XAVG(server.other.kbytes_out.kb)); - -+#ifdef HS_FEAT_ICAP -+ storeAppendPrintf(sentry, "icap.all.requests = %f/sec\n", -+ XAVG(icap.all.requests)); -+ storeAppendPrintf(sentry, "icap.all.errors = %f/sec\n", -+ XAVG(icap.all.errors)); -+ storeAppendPrintf(sentry, "icap.all.kbytes_in = %f/sec\n", -+ XAVG(icap.all.kbytes_in.kb)); -+ storeAppendPrintf(sentry, "icap.all.kbytes_out = %f/sec\n", -+ XAVG(icap.all.kbytes_out.kb)); -+#endif -+ - storeAppendPrintf(sentry, "icp.pkts_sent = %f/sec\n", - XAVG(icp.pkts_sent)); - storeAppendPrintf(sentry, "icp.pkts_recv = %f/sec\n", -@@ -1160,6 +1171,17 @@ statCountersDump(StoreEntry * sentry) - storeAppendPrintf(sentry, "server.other.kbytes_out = %d\n", - (int) f->server.other.kbytes_out.kb); - -+#if HS_FEAT_ICAP -+ storeAppendPrintf(sentry, "icap.all.requests = %d\n", -+ (int) f->icap.all.requests); -+ storeAppendPrintf(sentry, "icap.all.errors = %d\n", -+ (int) f->icap.all.errors); -+ storeAppendPrintf(sentry, "icap.all.kbytes_in = %d\n", -+ (int) f->icap.all.kbytes_in.kb); -+ storeAppendPrintf(sentry, "icap.all.kbytes_out = %d\n", -+ (int) f->icap.all.kbytes_out.kb); -+#endif -+ - storeAppendPrintf(sentry, "icp.pkts_sent = %d\n", - f->icp.pkts_sent); - storeAppendPrintf(sentry, "icp.pkts_recv = %d\n", -@@ -1459,8 +1481,6 @@ statClientRequests(StoreEntry * s) - storeAppendPrintf(s, "\tme: %s:%d\n", - inet_ntoa(conn->me.sin_addr), - ntohs(conn->me.sin_port)); -- storeAppendPrintf(s, "\tnrequests: %d\n", -- conn->nrequests); - storeAppendPrintf(s, "\tdefer: n %d, until %ld\n", - conn->defer.n, (long int) conn->defer.until); - } -Index: src/store.c -=================================================================== -RCS file: /cvsroot/squid/squid/src/store.c,v -retrieving revision 1.16.6.9 -retrieving revision 1.16.6.2.2.8 -diff -p -u -b -r1.16.6.9 -r1.16.6.2.2.8 ---- src/store.c 2 Sep 2005 02:13:43 -0000 1.16.6.9 -+++ src/store.c 12 Sep 2005 18:34:41 -0000 1.16.6.2.2.8 -@@ -520,7 +520,16 @@ storeAppend(StoreEntry * e, const char * - MemObject *mem = e->mem_obj; - assert(mem != NULL); - assert(len >= 0); -- assert(e->store_status == STORE_PENDING); -+ debug(20, 3) ("storeAppend: '%s'\n", storeKeyText(e->hash.key)); -+ if (e->store_status != STORE_PENDING) { -+ /* -+ * if we're not STORE_PENDING, then probably we got aborted -+ * and there should be NO clients on this entry -+ */ -+ assert(EBIT_TEST(e->flags, ENTRY_ABORTED)); -+ assert(e->mem_obj->nclients == 0); -+ return; -+ } - if (len) { - debug(20, 5) ("storeAppend: appending %d bytes for '%s'\n", - len, -Index: src/structs.h -=================================================================== -RCS file: /cvsroot/squid/squid/src/structs.h,v -retrieving revision 1.48.2.43 -retrieving revision 1.48.2.9.2.48 -diff -p -u -b -r1.48.2.43 -r1.48.2.9.2.48 ---- src/structs.h 4 Sep 2005 02:13:28 -0000 1.48.2.43 -+++ src/structs.h 30 Nov 2005 21:52:15 -0000 1.48.2.9.2.48 -@@ -384,6 +384,22 @@ struct _RemovalPolicySettings { - wordlist *args; - }; - -+#if HS_FEAT_ICAP -+struct _IcapConfig { -+ int onoff; -+ int preview_enable; -+ icap_service *service_head; -+ icap_class *class_head; -+ icap_access *access_head; -+ int preview_size; -+ int check_interval; -+ int send_client_ip; -+ int send_auth_user; -+ char *auth_scheme; -+}; -+ -+#endif /* HS_FEAT_ICAP */ -+ - struct _SquidConfig { - struct { - squid_off_t maxSize; -@@ -714,6 +730,9 @@ struct _SquidConfig { - char *store_dir_select_algorithm; - int sleep_after_fork; /* microseconds */ - external_acl *externalAclHelperList; -+#ifdef HS_FEAT_ICAP -+ IcapConfig icapcfg; -+#endif - }; - - struct _SquidConfig2 { -@@ -787,7 +806,10 @@ struct _fde { - } flags; - squid_off_t bytes_read; - squid_off_t bytes_written; -- int uses; /* ie # req's over persistent conn */ -+ struct { -+ int uses; -+ int type; -+ } pconn; - struct _fde_disk { - DWCB *wrt_handle; - void *wrt_handle_data; -@@ -982,6 +1004,130 @@ struct _http_state_flags { - unsigned int request_sent: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_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; -@@ -993,10 +1139,14 @@ struct _HttpStateData { - int fd; - http_state_flags flags; - FwdState *fwd; -+#ifdef HS_FEAT_ICAP -+ struct _IcapStateData *icap_writer; -+#endif - char *body_buf; - int body_buf_sz; - }; - -+ - struct _icpUdpData { - struct sockaddr_in address; - void *msg; -@@ -1092,6 +1242,7 @@ struct _clientHttpRequest { - unsigned int internal:1; - unsigned int done_copying:1; - unsigned int purging:1; -+ unsigned int did_icap_reqmod:1; - unsigned int hit:1; - } flags; - struct { -@@ -1100,6 +1251,9 @@ struct _clientHttpRequest { - } redirect; - dlink_node active; - squid_off_t maxBodySize; -+#if HS_FEAT_ICAP -+ IcapStateData *icap_reqmod; -+#endif - }; - - struct _ConnStateData { -@@ -1127,7 +1281,6 @@ struct _ConnStateData { - struct sockaddr_in me; - struct in_addr log_addr; - char rfc931[USER_IDENT_SZ]; -- int nrequests; - struct { - int n; - time_t until; -@@ -1678,6 +1831,9 @@ struct _request_t { - char *peer_login; /* Configured peer login:password */ - time_t lastmod; /* Used on refreshes */ - const char *vary_headers; /* Used when varying entities are detected. Changes how the store key is calculated */ -+#if HS_FEAT_ICAP -+ icap_class *class; -+#endif - BODY_HANDLER *body_reader; - void *body_reader_data; - }; -@@ -1784,7 +1940,11 @@ struct _StatCounters { - kb_t kbytes_in; - kb_t kbytes_out; - } all , http, ftp, other; -- } server; -+ } -+#if HS_FEAT_ICAP -+ icap, -+#endif -+ server; - struct { - int pkts_sent; - int queries_sent; -Index: src/typedefs.h -=================================================================== -RCS file: /cvsroot/squid/squid/src/typedefs.h,v -retrieving revision 1.25.6.8 -retrieving revision 1.25.6.1.6.13 -diff -p -u -b -r1.25.6.8 -r1.25.6.1.6.13 ---- src/typedefs.h 27 Mar 2005 02:16:17 -0000 1.25.6.8 -+++ src/typedefs.h 28 Mar 2005 18:05:08 -0000 1.25.6.1.6.13 -@@ -131,6 +131,15 @@ typedef struct _HttpHeaderStat HttpHeade - typedef struct _HttpBody HttpBody; - typedef struct _HttpReply HttpReply; - typedef struct _HttpStateData HttpStateData; -+#ifdef HS_FEAT_ICAP -+typedef struct _IcapStateData IcapStateData; -+typedef struct _IcapConfig IcapConfig; -+typedef struct _icap_service icap_service; -+typedef struct _icap_service_list icap_service_list; -+typedef struct _icap_class icap_class; -+typedef struct _icap_access icap_access; -+typedef struct _IcapOptData IcapOptData; -+#endif - typedef struct _icpUdpData icpUdpData; - typedef struct _clientHttpRequest clientHttpRequest; - typedef struct _ConnStateData ConnStateData; -Index: src/url.c -=================================================================== -RCS file: /cvsroot/squid/squid/src/url.c,v -retrieving revision 1.7.6.6 -retrieving revision 1.7.6.5.2.2 -diff -p -u -b -r1.7.6.6 -r1.7.6.5.2.2 ---- src/url.c 12 Nov 2005 03:13:48 -0000 1.7.6.6 -+++ src/url.c 23 Nov 2005 20:38:56 -0000 1.7.6.5.2.2 -@@ -103,6 +103,9 @@ const char *ProtocolStr[] = - "whois", - "internal", - "https", -+#ifdef HS_FEAT_ICAP -+ "icap", -+#endif - "TOTAL" - }; - -@@ -221,6 +224,10 @@ urlParseProtocol(const char *s) - return PROTO_WHOIS; - if (strcasecmp(s, "internal") == 0) - return PROTO_INTERNAL; -+#ifdef HS_FEAT_ICAP -+ if (strcasecmp(s, "icap") == 0) -+ return PROTO_ICAP; -+#endif - return PROTO_NONE; - } - -@@ -244,6 +251,10 @@ urlDefaultPort(protocol_t p) - return CACHE_HTTP_PORT; - case PROTO_WHOIS: - return 43; -+#ifdef HS_FEAT_ICAP -+ case PROTO_ICAP: -+ return 1344; -+#endif - default: - return 0; - } |