View | Details | Raw Unified | Return to bug 99750
Collapse All | Expand All

(-)Makefile (-146 / +99 lines)
Lines 1-23 Link Here
1
# New ports collection makefile for:	squid24
1
# New ports collection makefile for:	squid26
2
# Date created:		Tue Mar 27 14:56:08 CEST 2001
2
# Date created:		2006-06-01
3
# Whom:			Adrian Chadd <adrian@FreeBSD.org>
3
# Whom:			Thomas-Martin Seck <tmseck@netcologne.de>
4
#
4
#
5
# $FreeBSD: ports/www/squid/Makefile,v 1.188 2006/06/05 22:00:46 jmelo Exp $
5
# $FreeBSD$
6
#
6
#
7
# Tunables not (yet) configurable via 'make config':
7
# Tunables not (yet) configurable via 'make config':
8
# SQUID_{U,G}ID
8
# SQUID_{U,G}ID
9
#   Which user/group squid should run as (default: squid/squid).
9
#   Which user/group Squid should run as (default: squid/squid).
10
#   The user and group will be created if they do not already exist using
10
#   The user and group will be created if they do not already exist using
11
#   a uid:gid of 100:100.
11
#   a uid:gid of 100:100.
12
#   NOTE: before version 2.5.4_6, these settings defaulted to
12
#   NOTE: older versions of Squid defaulted to nobody/nogroup.
13
#   nobody/nogroup.
13
#   If you wish to run Squid as "nobody" (which is not recommended), please
14
#   If you wish to keep these settings, please define SQUID_UID=nobody and
14
#   define SQUID_UID=nobody and SQUID_GID=nogroup in your make environment
15
#   SQUID_GID=nogroup in your make environment before you start the update.
15
#   before you start the update or installation of this port.
16
#   NOTE2:
16
#
17
#   Before version 2.5.4_11 the numerical id chosen for SQUID_UID (and
18
#   SQUID_GID respectively) was the first free id greater than or equal 3128.
19
#   If you wish to move your squid user to id 100:100, run "make changeuser",
20
#   please see the changeuser target's definition for further information.
21
# SQUID_LANGUAGES
17
# SQUID_LANGUAGES
22
#   A list of languages for which error page files should be installed
18
#   A list of languages for which error page files should be installed
23
#   (default: all)
19
#   (default: all)
Lines 39-45 Link Here
39
#   `make SQUID_CONFIGURE_ARGS="--enable-dlmalloc --enable-truncate" install'
35
#   `make SQUID_CONFIGURE_ARGS="--enable-dlmalloc --enable-truncate" install'
40
#
36
#
41
#   The list below may be incomplete, please see the configure script
37
#   The list below may be incomplete, please see the configure script
42
#   in the squid source distribution for the complete list of additional
38
#   in the Squid source distribution for the complete list of additional
43
#   options.
39
#   options.
44
#   Note that you probably do not need to worry about these options in most
40
#   Note that you probably do not need to worry about these options in most
45
#   cases, they are included in case you want to experiment with them.
41
#   cases, they are included in case you want to experiment with them.
Lines 47-57 Link Here
47
#    --enable-dlmalloc
43
#    --enable-dlmalloc
48
#     Compile and use the malloc package from Doug Lea
44
#     Compile and use the malloc package from Doug Lea
49
#    --enable-gnuregex
45
#    --enable-gnuregex
50
#     Compile and use the supplied GNUregex routines instead of BSD regex.
46
#     Compile and use the supplied GNUregex routines instead of BSD regex
47
#     (not recommended).
51
#    --enable-xmalloc-statistics
48
#    --enable-xmalloc-statistics
52
#     Show malloc statistics in status page
49
#     Show malloc statistics in status page
53
#    --enable-time-hack
54
#     Optimize time updates to one per second rather than calling gettimeofday()
55
#    --enable-cachemgr-hostname=some.hostname
50
#    --enable-cachemgr-hostname=some.hostname
56
#     Set an explicit hostname in cachemgr.cgi
51
#     Set an explicit hostname in cachemgr.cgi
57
#    --enable-truncate
52
#    --enable-truncate
Lines 68-82 Link Here
68
#     of filedescriptors the resulting binary is expected to support.
63
#     of filedescriptors the resulting binary is expected to support.
69
#    --enable-ntlm-fail-open
64
#    --enable-ntlm-fail-open
70
#     Enable NTLM fail open, where a helper that fails one of the
65
#     Enable NTLM fail open, where a helper that fails one of the
71
#     Authentication steps can allow squid to still authenticate the user
66
#     Authentication steps can allow Squid to still authenticate the user
72
#
67
#    --enable-x-accelerator-vary
68
#     Enable support for the X-Accelerator-Vary HTTP header. Can be used
69
#     to indicate variance within an accelerator setup. Typically used
70
#     together with other code that adds custom HTTP headers to the
71
#     requests.
72
#    --enable-auth-on-acceleration
73
#     Enable authentication in accelerators.
74
#    --enable-forward-log
75
#     Enable experimental forward_log directive.
76
#    --enable-multicast-miss
77
#     Enable experimental multicast notification of cachemisses.
73
78
74
PORTNAME=	squid
79
PORTNAME=	squid
75
PORTVERSION=	2.5.14
80
PORTVERSION=	2.6.1
76
PORTREVISION=	1
77
CATEGORIES=	www
81
CATEGORIES=	www
78
MASTER_SITES=	\
82
MASTER_SITES=	ftp://ftp.squid-cache.org/pub/%SUBDIR%/ \
79
		ftp://ftp.squid-cache.org/pub/%SUBDIR%/ \
80
		ftp://archive.progeny.com/squid/%SUBDIR%/ \
83
		ftp://archive.progeny.com/squid/%SUBDIR%/ \
81
		ftp://mirrors.24-7-solutions.net/pub/squid/%SUBDIR%/ \
84
		ftp://mirrors.24-7-solutions.net/pub/squid/%SUBDIR%/ \
82
		ftp://sunsite.auc.dk/pub/infosystems/squid/%SUBDIR%/ \
85
		ftp://sunsite.auc.dk/pub/infosystems/squid/%SUBDIR%/ \
Lines 86-105 Link Here
86
		ftp://ftp.ccs.neu.edu/pub/mirrors/squid.nlanr.net/pub/%SUBDIR%/ \
89
		ftp://ftp.ccs.neu.edu/pub/mirrors/squid.nlanr.net/pub/%SUBDIR%/ \
87
		${MASTER_SITE_RINGSERVER:S,%SUBDIR%,net/www/squid/&,}
90
		${MASTER_SITE_RINGSERVER:S,%SUBDIR%,net/www/squid/&,}
88
MASTER_SITE_SUBDIR=	squid-2/STABLE
91
MASTER_SITE_SUBDIR=	squid-2/STABLE
89
DISTNAME=	squid-2.5.STABLE14
92
DISTNAME=	squid-2.6.STABLE1
90
DIST_SUBDIR=	squid2.5
93
DIST_SUBDIR=	squid2.6
91
94
92
PATCH_SITES=	http://www.squid-cache.org/Versions/v2/2.5/bugs/
95
PATCH_SITES=	http://www.squid-cache.org/%SUBDIR%/ \
93
PATCHFILES=	squid-2.5.STABLE14-httpReplyDestroy.patch
96
		http://www2.us.squid-cache.org/%SUBDIR%/ \
97
		http://www3.us.squid-cache.org/%SUBDIR%/ \
98
		http://www1.at.squid-cache.org/%SUBDIR%/ \
99
		http://www2.nl.squid-cache.org/%SUBDIR%/ \
100
		http://www1.ru.squid-cache.org/%SUBDIR%/ \
101
		http://www1.uk.squid-cache.org/%SUBDIR%/ \
102
		http://www1.jp.squid-cache.org/%SUBDIR%/ \
103
		http://www1.tw.squid-cache.org/%SUBDIR%/
104
PATCH_SITE_SUBDIR=	Versions/v2/2.6/bugs
105
PATCHFILES=
94
PATCH_DIST_STRIP=	-p1
106
PATCH_DIST_STRIP=	-p1
95
107
96
MAINTAINER=	tmseck@netcologne.de
108
MAINTAINER=	tmseck@netcologne.de
97
COMMENT=	The successful WWW proxy cache and accelerator
109
COMMENT=	HTTP Caching Proxy
98
110
99
CONFLICTS=	squid-2.[^5]*
111
LATEST_LINK=	squid26
112
113
CONFLICTS=	squid-2.[^6]*
100
GNU_CONFIGURE=	yes
114
GNU_CONFIGURE=	yes
101
USE_BZIP2=	yes
115
USE_BZIP2=	yes
102
USE_PERL5=	yes
116
USE_PERL5=	yes
117
USE_RC_SUBR=	squid
103
118
104
SQUID_UID?=	squid
119
SQUID_UID?=	squid
105
SQUID_GID?=	squid
120
SQUID_GID?=	squid
Lines 114-133 Link Here
114
		SQUID_SASL_AUTH "Install SASL authentication helpers" off \
129
		SQUID_SASL_AUTH "Install SASL authentication helpers" off \
115
		SQUID_DELAY_POOLS "Enable delay pools" off \
130
		SQUID_DELAY_POOLS "Enable delay pools" off \
116
		SQUID_SNMP "Enable SNMP support" off \
131
		SQUID_SNMP "Enable SNMP support" off \
117
		SQUID_CARP "Enable CARP support" off \
132
		SQUID_CARP "Enable CARP support" on \
118
		SQUID_SSL "Enable SSL support for reverse proxies" off \
133
		SQUID_SSL "Enable SSL support for reverse proxies" off \
119
		SQUID_PINGER "Install the icmp helper" off \
134
		SQUID_PINGER "Install the icmp helper" off \
120
		SQUID_DNS_HELPER "Use the old 'dnsserver' helper" off \
135
		SQUID_DNS_HELPER "Use the old 'dnsserver' helper" off \
121
		SQUID_HTCP "Enable HTCP support" off \
136
		SQUID_HTCP "Enable HTCP support" off \
122
		SQUID_VIA_DB "Enable forward/via database" off \
137
		SQUID_VIA_DB "Enable forward/via database" off \
123
		SQUID_CACHE_DIGESTS "Enable cache digests" off \
138
		SQUID_CACHE_DIGESTS "Enable cache digests" off \
124
		SQUID_WCCP "Enable Web Cache Coordination Protocol" on \
139
		SQUID_WCCP "Enable Web Cache Coordination Prot. v1" on \
125
		SQUID_UNDERSCORES "Allow underscores in hostnames" on \
140
		SQUID_WCCPV2 "Enable Web Cache Coordination Prot. v2" off \
126
		SQUID_CHECK_HOSTNAME "Do hostname checking" on \
127
		SQUID_STRICT_HTTP "Be strictly HTTP compliant" off \
141
		SQUID_STRICT_HTTP "Be strictly HTTP compliant" off \
128
		SQUID_IDENT "Enable ident (RFC 931) lookups" on \
142
		SQUID_IDENT "Enable ident (RFC 931) lookups" on \
143
		SQUID_REFERER_LOG "Enable Referer-header logging" off \
129
		SQUID_USERAGENT_LOG "Enable User-Agent-header logging" off \
144
		SQUID_USERAGENT_LOG "Enable User-Agent-header logging" off \
130
		SQUID_CUSTOM_LOG "Enable custom log format" off \
131
		SQUID_ARP_ACL "Enable ACLs based on ethernet address" off \
145
		SQUID_ARP_ACL "Enable ACLs based on ethernet address" off \
132
		SQUID_PF "Enable transparent proxying with PF" off \
146
		SQUID_PF "Enable transparent proxying with PF" off \
133
		SQUID_IPFILTER "Enable transp. proxying with IPFilter" off \
147
		SQUID_IPFILTER "Enable transp. proxying with IPFilter" off \
Lines 135-143 Link Here
135
		SQUID_ICAP "Enable ICAP client functionality" off \
149
		SQUID_ICAP "Enable ICAP client functionality" off \
136
		SQUID_AUFS "Enable the aufs storage scheme" off \
150
		SQUID_AUFS "Enable the aufs storage scheme" off \
137
		SQUID_COSS "Enable the COSS storage scheme" off \
151
		SQUID_COSS "Enable the COSS storage scheme" off \
152
		SQUID_KQUEUE "Use kqueue(2) instead of poll(2)" on \
138
		SQUID_LARGEFILE "Support log and cache files >2GB" off \
153
		SQUID_LARGEFILE "Support log and cache files >2GB" off \
139
		SQUID_STACKTRACES "Create backtraces on fatal errors" off \
154
		SQUID_STACKTRACES "Create backtraces on fatal errors" off
140
		SQUID_RCNG "Install an rc.d style startup script" on
141
155
142
etc_files=	squid/cachemgr.conf.default \
156
etc_files=	squid/cachemgr.conf.default \
143
		squid/mib.txt squid/mime.conf.default \
157
		squid/mib.txt squid/mime.conf.default \
Lines 165-201 Link Here
165
		ERR_SOCKET_FAILURE ERR_TOO_BIG ERR_UNSUP_REQ \
179
		ERR_SOCKET_FAILURE ERR_TOO_BIG ERR_UNSUP_REQ \
166
		ERR_URN_RESOLVE ERR_WRITE_ERROR ERR_ZERO_SIZE_OBJECT
180
		ERR_URN_RESOLVE ERR_WRITE_ERROR ERR_ZERO_SIZE_OBJECT
167
181
168
libexec=	cachemgr.cgi digest_pw_auth diskd ip_user_check \
182
libexec=	cachemgr.cgi digest_pw_auth diskd-daemon ip_user_check \
169
		msnt_auth ncsa_auth ntlm_auth \
183
		msnt_auth ncsa_auth ntlm_auth \
170
		pam_auth smb_auth smb_auth.sh squid_unix_group \
184
		pam_auth smb_auth smb_auth.sh squid_session squid_unix_group \
171
		wb_auth wb_group wb_ntlmauth wbinfo_group.pl
185
		wbinfo_group.pl
172
.if !defined(SQUID_CONFIGURE_ARGS) || ${SQUID_CONFIGURE_ARGS:M*--disable-unlinkd*} == ""
186
.if !defined(SQUID_CONFIGURE_ARGS) || ${SQUID_CONFIGURE_ARGS:M*--disable-unlinkd*} == ""
173
libexec+=	unlinkd
187
libexec+=	unlinkd
174
.endif
188
.endif
175
189
176
sbin=		RunAccel RunCache squidclient squid
190
sbin=		RunCache squidclient squid
177
191
178
CONFIGURE_ARGS=	--bindir=${PREFIX}/sbin  --sysconfdir=${PREFIX}/etc/squid \
192
CONFIGURE_ARGS=	--bindir=${PREFIX}/sbin  \
193
		--sbindir=${PREFIX}/sbin  \
179
		--datadir=${PREFIX}/etc/squid \
194
		--datadir=${PREFIX}/etc/squid \
180
		--libexecdir=${PREFIX}/libexec/squid \
195
		--libexecdir=${PREFIX}/libexec/squid \
181
		--localstatedir=${PREFIX}/squid \
196
		--localstatedir=${PREFIX}/squid \
182
		--enable-removal-policies="lru heap"
197
		--sysconfdir=${PREFIX}/etc/squid \
198
		--enable-removal-policies="lru heap" \
199
		--disable-linux-netfilter \
200
		--disable-linux-tproxy \
201
		--disable-epoll
183
202
184
.include <bsd.port.pre.mk>
203
.include <bsd.port.pre.mk>
185
204
186
# Authentication methods and modules:
205
# Authentication methods and modules:
187
206
188
basic_auth=	NCSA PAM MSNT SMB winbind
207
basic_auth=	NCSA PAM MSNT SMB
189
external_acl=	ip_user unix_group wbinfo_group winbind_group
208
digest_auth=	password
190
MAN8+=		pam_auth.8 squid_unix_group.8
209
external_acl=	ip_user session unix_group wbinfo_group
210
MAN8+=		ncsa_auth.8 pam_auth.8 squid_session.8 squid_unix_group.8
191
.if defined(WITH_SQUID_LDAP_AUTH)
211
.if defined(WITH_SQUID_LDAP_AUTH)
192
USE_OPENLDAP=	yes
212
USE_OPENLDAP=	yes
193
CFLAGS+=	-I${LOCALBASE}/include
213
CFLAGS+=	-I${LOCALBASE}/include
194
LDFLAGS+=	-L${LOCALBASE}/lib
214
LDFLAGS+=	-L${LOCALBASE}/lib
195
MAN8+=		squid_ldap_auth.8 squid_ldap_group.8
215
MAN8+=		squid_ldap_auth.8 squid_ldap_group.8
196
basic_auth+=	LDAP
216
basic_auth+=	LDAP
217
digest_auth+=	ldap
197
external_acl+=	ldap_group
218
external_acl+=	ldap_group
198
libexec+=	squid_ldap_auth squid_ldap_group
219
libexec+=	digest_ldap_auth squid_ldap_auth squid_ldap_group
199
.endif
220
.endif
200
.if defined(WITH_SQUID_SASL_AUTH)
221
.if defined(WITH_SQUID_SASL_AUTH)
201
LIB_DEPENDS+=	sasl2.2:${PORTSDIR}/security/cyrus-sasl2
222
LIB_DEPENDS+=	sasl2.2:${PORTSDIR}/security/cyrus-sasl2
Lines 211-221 Link Here
211
.endif
232
.endif
212
CONFIGURE_ARGS+=	--enable-auth="basic ntlm digest" \
233
CONFIGURE_ARGS+=	--enable-auth="basic ntlm digest" \
213
			--enable-basic-auth-helpers="${basic_auth}" \
234
			--enable-basic-auth-helpers="${basic_auth}" \
214
			--enable-digest-auth-helpers="password" \
235
			--enable-digest-auth-helpers="${digest_auth}" \
215
			--enable-external-acl-helpers="${external_acl}" \
236
			--enable-external-acl-helpers="${external_acl}" \
216
			--enable-ntlm-auth-helpers="SMB winbind"
237
			--enable-ntlm-auth-helpers="SMB"
217
238
218
# Selection of storage schemes:
239
# Storage schemes:
219
240
220
storage_schemes=	ufs diskd null
241
storage_schemes=	ufs diskd null
221
.if defined(WITH_SQUID_AUFS)
242
.if defined(WITH_SQUID_AUFS)
Lines 227-233 Link Here
227
.endif
248
.endif
228
.if defined(WITH_SQUID_COSS)
249
.if defined(WITH_SQUID_COSS)
229
storage_schemes+=	coss
250
storage_schemes+=	coss
230
CONFIGURE_ARGS+=	--with-aio
251
CONFIGURE_ARGS+=	--enable-coss-aio-ops
231
.endif
252
.endif
232
CONFIGURE_ARGS+=	--enable-storeio="${storage_schemes}"
253
CONFIGURE_ARGS+=	--enable-storeio="${storage_schemes}"
233
254
Lines 239-251 Link Here
239
.if defined(WITH_SQUID_SNMP)
260
.if defined(WITH_SQUID_SNMP)
240
CONFIGURE_ARGS+=	--enable-snmp
261
CONFIGURE_ARGS+=	--enable-snmp
241
.endif
262
.endif
242
.if defined(WITH_SQUID_CARP)
263
.if defined(WITHOUT_SQUID_CARP)
243
CONFIGURE_ARGS+=	--enable-carp
264
CONFIGURE_ARGS+=	--disable-carp
244
.endif
265
.endif
245
.if defined(WITH_SQUID_SSL)
266
.if defined(WITH_SQUID_SSL)
246
# we need to .include bsd.openssl.mk manually here because USE_OPENSSL only
267
# we need to .include bsd.openssl.mk manually here.because USE_OPENSSL only
247
# works when it is defined before bsd.port{.pre}.mk is .included and this is
268
# works when it is defined before bsd.port{.pre}.mk is .included.
248
# not possible when using OPTIONS
269
# This makes it currently impossible to combine this macro with OPTIONS to
270
# conditionally include OpenSSL support.
249
.include "${PORTSDIR}/Mk/bsd.openssl.mk"
271
.include "${PORTSDIR}/Mk/bsd.openssl.mk"
250
CONFIGURE_ARGS+=	--enable-ssl \
272
CONFIGURE_ARGS+=	--enable-ssl \
251
			--with-openssl="${OPENSSLBASE}"
273
			--with-openssl="${OPENSSLBASE}"
Lines 272-295 Link Here
272
.if defined(WITHOUT_SQUID_WCCP)
294
.if defined(WITHOUT_SQUID_WCCP)
273
CONFIGURE_ARGS+=	--disable-wccp
295
CONFIGURE_ARGS+=	--disable-wccp
274
.endif
296
.endif
275
.if !defined(WITHOUT_SQUID_UNDERSCORES)
297
.if defined(WITH_SQUID_WCCPV2)
276
CONFIGURE_ARGS+=	--enable-underscores
298
CONFIGURE_ARGS+=	--enable-wccpv2
277
.endif
299
.endif
278
.if defined(WITHOUT_SQUID_CHECK_HOSTNAME)
279
CONFIGURE_ARGS+=	--disable-hostname-checks
280
.endif
281
.if defined(WITH_SQUID_STRICT_HTTP)
300
.if defined(WITH_SQUID_STRICT_HTTP)
282
CONFIGURE_ARGS+=	--disable-http-violations
301
CONFIGURE_ARGS+=	--disable-http-violations
283
.endif
302
.endif
284
.if defined(WITHOUT_SQUID_IDENT)
303
.if defined(WITHOUT_SQUID_IDENT)
285
CONFIGURE_ARGS+=	--disable-ident-lookups
304
CONFIGURE_ARGS+=	--disable-ident-lookups
286
.endif
305
.endif
306
.if defined(WITH_SQUID_REFERER_LOG)
307
CONFIGURE_ARGS+=	--enable-referer-log
308
.endif
287
.if defined(WITH_SQUID_USERAGENT_LOG)
309
.if defined(WITH_SQUID_USERAGENT_LOG)
288
CONFIGURE_ARGS+=	--enable-useragent-log
310
CONFIGURE_ARGS+=	--enable-useragent-log
289
.endif
311
.endif
290
.if defined(WITH_SQUID_CUSTOM_LOG)
291
EXTRA_PATCHES+=		${PATCHDIR}/customlog-2.5.patch
292
.endif
293
.if defined(WITH_SQUID_ARP_ACL)
312
.if defined(WITH_SQUID_ARP_ACL)
294
CONFIGURE_ARGS+=	--enable-arp-acl
313
CONFIGURE_ARGS+=	--enable-arp-acl
295
.endif
314
.endif
Lines 313-357 Link Here
313
.endif
332
.endif
314
.endif
333
.endif
315
.if defined(WITH_SQUID_FOLLOW_XFF)
334
.if defined(WITH_SQUID_FOLLOW_XFF)
316
EXTRA_PATCHES+=		${PATCHDIR}/follow_xff-2.5.patch \
317
			${PATCHDIR}/follow_xff-configure.patch
318
CONFIGURE_ARGS+=	--enable-follow-x-forwarded-for
335
CONFIGURE_ARGS+=	--enable-follow-x-forwarded-for
319
.endif
336
.endif
320
.if defined(WITH_SQUID_ICAP)
337
.if defined(WITH_SQUID_ICAP)
321
EXTRA_PATCHES+=		${PATCHDIR}/icap-2.5-core.patch \
338
IGNORE=		patches for ICAP support are not yet updated
322
			${PATCHDIR}/icap-2.5-bootstrap.patch
339
EXTRA_PATCHES+=	
323
CONFIGURE_ARGS+=	--enable-icap-support
340
#CONFIGURE_ARGS+=	--enable-icap-support
324
error_files+=		ERR_ICAP_FAILURE
341
#error_files+=		ERR_ICAP_FAILURE
325
.endif
342
.endif
343
.if !defined(WITHOUT_SQUID_KQUEUE)
344
CONFIGURE_ARGS+=	--enable-kqueue
345
.else
346
CONFIGURE_ARGS+=	--disable-kqueue
347
.endif
326
.if defined(WITH_SQUID_LARGEFILE)
348
.if defined(WITH_SQUID_LARGEFILE)
327
CONFIGURE_ARGS+=	--with-large-files --enable-large-cache-files
349
CONFIGURE_ARGS+=	--with-large-files --enable-large-cache-files
328
.endif
350
.endif
329
.if defined(WITH_SQUID_STACKTRACES)
351
.if defined(WITH_SQUID_STACKTRACES) || defined(WITH_DEBUG)
330
CONFIGURE_ARGS+=	--enable-stacktraces
352
CONFIGURE_ARGS+=	--enable-stacktraces
331
CFLAGS+=	-g
353
CFLAGS+=	-g
332
STRIP=			""
354
STRIP=			""
333
.endif
355
.endif
334
.if !defined(WITHOUT_SQUID_RCNG)
335
USE_RC_SUBR=	squid.sh
336
rc_del=		rcold
337
rc_state=	rcng
338
.else
339
SUB_FILES+=	squid.sh
340
etc_files+=	rc.d/squid.sh
341
rc_del=		rcng
342
rc_state=	rcold
343
.endif
344
356
345
# Languages:
357
# Languages:
346
#
358
#
347
# If you do not define SQUID_LANGUAGES yourself, all available language files
359
# If you do not define SQUID_LANGUAGES yourself, all available language files
348
# will be installed; the default language will be English.
360
# will be installed; the default language will be English.
349
361
350
SQUID_LANGUAGES?=	\
362
SQUID_LANGUAGES?=	Azerbaijani Bulgarian Catalan Czech Danish Dutch \
351
	Azerbaijani Bulgarian Catalan Czech Danish Dutch English Estonian Finnish      \
363
			English Estonian Finnish French German Greek Hebrew \
352
	French German Greek Hebrew Hungarian Italian Japanese Korean Lithuanian \
364
			Hungarian Italian Japanese Korean Lithuanian \
353
	Polish Portuguese Romanian Russian-1251 Russian-koi8-r Serbian     \
365
			Polish Portuguese Romanian Russian-1251 Russian-koi8-r \
354
	Simplify_Chinese Slovak Spanish Swedish Traditional_Chinese Turkish
366
			Serbian Simplify_Chinese Slovak Spanish Swedish \
367
			Traditional_Chinese Turkish
355
SQUID_DEFAULT_LANG?=	English
368
SQUID_DEFAULT_LANG?=	English
356
CONFIGURE_ARGS+=	--enable-err-languages="${SQUID_LANGUAGES}" \
369
CONFIGURE_ARGS+=	--enable-err-languages="${SQUID_LANGUAGES}" \
357
			--enable-default-err-language=${SQUID_DEFAULT_LANG}
370
			--enable-default-err-language=${SQUID_DEFAULT_LANG}
Lines 385-415 Link Here
385
# Prevent installation of .orig files by deleting them.
398
# Prevent installation of .orig files by deleting them.
386
	@${FIND} ${WRKSRC} -name '*.bak' -delete
399
	@${FIND} ${WRKSRC} -name '*.bak' -delete
387
	@${FIND} ${WRKSRC} -name '*.orig' -delete
400
	@${FIND} ${WRKSRC} -name '*.orig' -delete
388
# create the start script:
389
	@${REINPLACE_CMD} \
390
	    -e '/--begin ${rc_del}/,/--end ${rc_del}/d' \
391
	    -e '/--.*${rc_state}/d' ${WRKDIR}/squid.sh
392
# create variable information in pkg-message:
393
	@${REINPLACE_CMD} \
394
	    -e '/--begin ${rc_del}/,/--end ${rc_del}/d' \
395
	    -e '/--.*${rc_state}/d' ${PKGMESSAGE}
396
401
397
pre-su-install:
402
pre-su-install:
398
	@${SETENV} ${SCRIPTS_ENV} PKG_PREFIX=${PREFIX} \
403
	@${SETENV} ${SCRIPTS_ENV} PKG_PREFIX=${PREFIX} \
399
	    ${SH} ${PKGINSTALL} ${PKGNAME} PRE-INSTALL
404
	    ${SH} ${PKGINSTALL} ${PKGNAME} PRE-INSTALL
400
405
401
post-install:
406
post-install:
402
# Create cachemgr.conf.default manually since squid's install routine
403
# unfortunately fails to do so:
404
	${INSTALL_DATA} ${WRKSRC}/src/cachemgr.conf \
405
	    ${PREFIX}/etc/squid/cachemgr.conf.default
406
.if defined(WITH_SQUID_PINGER)
407
.if defined(WITH_SQUID_PINGER)
407
	${CHMOD} 4510 ${PREFIX}/libexec/squid/pinger; \
408
	${CHMOD} 4510 ${PREFIX}/libexec/squid/pinger; \
408
	${CHGRP} ${SQUID_GID} ${PREFIX}/libexec/squid/pinger
409
	${CHGRP} ${SQUID_GID} ${PREFIX}/libexec/squid/pinger
409
.endif
410
.endif
410
.if defined(WITHOUT_SQUID_RCNG)
411
	${INSTALL_SCRIPT} ${WRKDIR}/squid.sh ${PREFIX}/etc/rc.d/
412
.endif
413
.if !defined(NOPORTDOCS)
411
.if !defined(NOPORTDOCS)
414
	@${MKDIR} ${DOCSDIR}
412
	@${MKDIR} ${DOCSDIR}
415
	cd ${WRKSRC} && ${INSTALL_DATA} ${docs} ${DOCSDIR}
413
	cd ${WRKSRC} && ${INSTALL_DATA} ${docs} ${DOCSDIR}
Lines 421-470 Link Here
421
	@${ECHO_CMD} ""
419
	@${ECHO_CMD} ""
422
	@${CAT} ${PKGMESSAGE}
420
	@${CAT} ${PKGMESSAGE}
423
	@${ECHO_CMD} ""
421
	@${ECHO_CMD} ""
424
changeuser:
425
# Recover from the problem that earlier versions of this port created the
426
# squid pseudo-user with an id greater than 999 which is not allowed in
427
# FreeBSD's ports system. The port now uses id 100:100.
428
# NOTE:
429
# This target assumes that SQUID_GID is the primary group of SQUID_UID. If you
430
# have a different setup, do not run this target!
431
.if ${SQUID_UID:L} == nobody
432
	@${ECHO_CMD} "'nobody' is a system user, you do not need to execute"; \
433
	${ECHO_CMD} "this target!"
434
	${FALSE}
435
.endif
436
	@if [ `${ID} -u` -ne 0 ]; \
437
	then ${ECHO_CMD} "Sorry, you must be root to use this target."; ${FALSE}; fi; \
438
	current_uid=`id -u ${SQUID_UID}`; \
439
	current_gid=`pw groupshow ${SQUID_GID}|cut -f 3 -d :`; \
440
	${ECHO_CMD} "I will remove this user:"; \
441
	${ID} -P $${current_uid}; \
442
	${ECHO_CMD} "and this group:"; \
443
	pw groupshow ${SQUID_GID}; \
444
	${ECHO_CMD} "I will then re-create them with a user and group id of 100."; \
445
	${ECHO_CMD} "Then all files and directories under ${PREFIX} and /var that"; \
446
	${ECHO_CMD} "are owned by uid $${current_uid} will be chown(1)'ed."; \
447
	${ECHO_CMD} "After that, all files and directories that were accessible"; \
448
	${ECHO_CMD} "by group $${current_gid} will chgrp(1)'ed respectively."; \
449
	${ECHO_CMD} "Note that this assumes group '${SQUID_GID}' to be the primary"; \
450
	${ECHO_CMD} "group of user '${SQUID_UID}'. If you have a different setup"; \
451
	${ECHO_CMD} "please abort this target now."; \
452
	read -p "Press RETURN to continue or CTRL-C to abort:" dummy ; \
453
	${ECHO_CMD} "OK, here we go:"; \
454
	${ECHO_CMD} "deleting user $${current_uid} and his primary group..."; \
455
	pw userdel -u $${current_uid}; \
456
	${ECHO_CMD} "adding user ${SQUID_UID} with id 100..."; \
457
	pw groupadd -n ${SQUID_GID} -g 100; \
458
	pw useradd -n ${SQUID_UID} -u 100 -c "squid caching-proxy pseudo user" \
459
	    -d ${PREFIX}/squid -s /sbin/nologin -h - ; \
460
	${ECHO_CMD} "chown(1)'ing everything under ${PREFIX} from $${current_uid} to 100..."; \
461
	${FIND} -H ${PREFIX} -user $${current_uid} -exec ${CHOWN} 100 {} \; ; \
462
	${ECHO_CMD} "chgrp(1)'ing everything under ${PREFIX} from $${current_gid} to 100..."; \
463
	${FIND} -H ${PREFIX} -group $${current_gid} -exec ${CHOWN} :100 {} \; ; \
464
	${ECHO_CMD} "chown(1)'ing everything under /var from $${current_uid} to 100..."; \
465
	${FIND} -H /var -user $${current_uid} -exec ${CHOWN} 100 {} \; ; \
466
	${ECHO_CMD} "chgrp(1)'ing everything under /var from $${current_gid} to 100..."; \
467
	${FIND} -H /var -group $${current_gid} -exec ${CHOWN} :100 {} \; ; \
468
	${ECHO_CMD} "Finished."
469
422
470
.include <bsd.port.post.mk>
423
.include <bsd.port.post.mk>
(-)distinfo (-6 / +3 lines)
Lines 1-6 Link Here
1
MD5 (squid2.5/squid-2.5.STABLE14.tar.bz2) = f413e0b887a5f9b2a75350243ed5564c
1
MD5 (squid2.6/squid-2.6.STABLE1.tar.bz2) = d6bb23a67b0475cca11d4af8d574d054
2
SHA256 (squid2.5/squid-2.5.STABLE14.tar.bz2) = c4eaee0e5ee42f46060217df9a88d628d244c0a543feab8296e44269e57ec7bd
2
SHA256 (squid2.6/squid-2.6.STABLE1.tar.bz2) = a9efea26f1c3966dff69f80c271a73562afed5c65929d69dab713308dd402ba9
3
SIZE (squid2.5/squid-2.5.STABLE14.tar.bz2) = 1073745
3
SIZE (squid2.6/squid-2.6.STABLE1.tar.bz2) = 1212556
4
MD5 (squid2.5/squid-2.5.STABLE14-httpReplyDestroy.patch) = 1529f8b0170e24b26353578778435bd4
5
SHA256 (squid2.5/squid-2.5.STABLE14-httpReplyDestroy.patch) = 9e99132b8efb07e3465d5e33749aa450daecfa3acde73755b6a3589d09d19285
6
SIZE (squid2.5/squid-2.5.STABLE14-httpReplyDestroy.patch) = 1277
(-)pkg-descr (-12 / +7 lines)
Lines 1-15 Link Here
1
This is the Squid Internet Object Cache developed by the National
1
Squid is a high-performance proxy caching server for web clients,
2
Laboratory for Applied Networking Research (NLANR) and Internet
2
supporting FTP, gopher, and HTTP data objects. Unlike traditional
3
volunteers.  This software is freely available for anyone to use.
3
caching software, Squid handles all requests in a single, non-blocking,
4
I/O-driven process.
4
5
5
This software is based on the Harvest Object Cache developed by
6
Squid supports SSL, extensive access controls, and full request logging.
6
the University of Colorado and the University of Southern California.
7
By using the lightweight Internet Cache Protocol, Squid caches can be
7
The Harvest home page is http://harvest.cs.colorado.edu/.
8
arranged in a hierarchy or mesh for additional bandwidth savings.
8
9
9
ARPA funding for the Harvest project has ended, the squid project has
10
continued development of the cache where Harvest finished.
11
12
This port provides many configuration options, most of which are
13
available via 'make config'.
14
15
WWW: http://www.squid-cache.org/
10
WWW: http://www.squid-cache.org/
(-)files/pkg-deinstall.in (-7 / +6 lines)
Lines 1-6 Link Here
1
#!/bin/sh
1
#!/bin/sh
2
#
2
#
3
# $FreeBSD: ports/www/squid/files/pkg-deinstall.in,v 1.1 2006/03/18 17:11:13 pav Exp $
3
# $FreeBSD$
4
#
4
#
5
5
6
PATH=/bin:/usr/bin:/usr/sbin
6
PATH=/bin:/usr/bin:/usr/sbin
Lines 16-35 Link Here
16
	echo "===> post-deinstallation information for $1:"
16
	echo "===> post-deinstallation information for $1:"
17
	echo ""
17
	echo ""
18
	echo "     Note:"
18
	echo "     Note:"
19
	echo "     squid related user accounts and groups were not removed."
19
	echo "     Squid related user accounts and groups were not removed."
20
	echo ""
20
	echo ""
21
	echo "     To remove the '%%SQUID_UID%%' user and the '%%SQUID_GID%%' group which were"
21
	echo "     To remove the '%%SQUID_UID%%' user and the '%%SQUID_GID%%' group which were"
22
	echo "     created by a default installation of this package, run"
22
	echo "     created by a default installation of this package, run"
23
	echo ""
23
	echo ""
24
	echo "     pw userdel -r -n %%SQUID_UID%% -u 100"
24
	echo "     pw userdel -n %%SQUID_UID%% -u 100"
25
	echo ""
26
	if  [ -d ${PKG_PREFIX}/squid -o -d ${PKG_PREFIX}/etc/squid ] ; then
25
	if  [ -d ${PKG_PREFIX}/squid -o -d ${PKG_PREFIX}/etc/squid ] ; then
27
		echo ""
26
		echo ""
28
		echo "     To ease updates, the cache and log directories and"
27
		echo "     In order to ease updates the cache and log directories"
29
		echo "     all configuration files modified by you were preserved."
28
		echo "     and all configuration files modified by you were preserved."
30
		echo ""
29
		echo ""
31
		echo "     Please remove them manually if you do not want to use"
30
		echo "     Please remove them manually if you do not want to use"
32
	       	echo "     squid any longer."
31
	       	echo "     Squid any longer."
33
	fi
32
	fi
34
	echo ""
33
	echo ""
35
	;;
34
	;;
(-)files/pkg-message.in (-7 / +14 lines)
Lines 1-9 Link Here
1
     o You can find the configuration files for this package in the
1
     o You can find the configuration files for this package in the
2
       directory %%PREFIX%%/etc/squid.
2
       directory %%PREFIX%%/etc/squid.
3
     
3
4
     o A cache directory has been created in %%PREFIX%%/squid/cache.
4
     o A cache directory has been created in %%PREFIX%%/squid/cache.
5
       Log files will be written to %%PREFIX%%/squid/logs.
5
       Log files will be written to %%PREFIX%%/squid/logs.
6
     
6
7
       Note:
7
       Note:
8
       You must initialize new cache directories before you can start
8
       You must initialize new cache directories before you can start
9
       squid.  Do this by running "squid -z" as 'root' or '%%SQUID_UID%%'.
9
       squid.  Do this by running "squid -z" as 'root' or '%%SQUID_UID%%'.
Lines 13-24 Link Here
13
     o The default configuration will deny everyone access to the
13
     o The default configuration will deny everyone access to the
14
       proxy service. Edit the "http_access" directives in
14
       proxy service. Edit the "http_access" directives in
15
       %%PREFIX%%/etc/squid.conf to suit your needs.
15
       %%PREFIX%%/etc/squid.conf to suit your needs.
16
--begin rcng
17
16
18
     Please note that the squid start script is an rc.d style script.
17
     Please note that the Squid start script is an rc.d style script.
19
     This means that squid will not start automatically at boot time.
18
     This means that Squid will not start automatically at boot
19
     time unless it is explicitly enabled.
20
20
21
     To enable squid, set squid_enable=yes in either
21
     To enable Squid, set squid_enable=yes in either
22
     /etc/rc.conf, /etc/rc.conf.local or /etc/rc.conf.d/squid
22
     /etc/rc.conf, /etc/rc.conf.local or /etc/rc.conf.d/squid
23
     Please see %%PREFIX%%/etc/rc.d/squid(.sh) for further details.
23
     Please see %%PREFIX%%/etc/rc.d/squid(.sh) for further details.
24
--end rcng
24
25
     Note:
26
     If you just updated your Squid installation from 2.5 or earlier,
27
     make sure to check your Squid configuration against the 2.6 default
28
     configuration file %%PREFIX%%/etc/squid/squid.conf.default.
29
30
     Additionally, you should check your configuration by calling
31
     'squid -f /path/to/squid.conf -k parse' before starting Squid.
(-)files/pkg-install.in (-60 / +3 lines)
Lines 1-6 Link Here
1
#!/bin/sh
1
#!/bin/sh
2
#
2
#
3
# $FreeBSD: ports/www/squid/files/pkg-install.in,v 1.1 2006/03/18 17:11:13 pav Exp $
3
# $FreeBSD$
4
#
4
#
5
5
6
PATH=/bin:/usr/bin:/usr/sbin
6
PATH=/bin:/usr/bin:/usr/sbin
Lines 16-33 Link Here
16
squid_group="%%SQUID_GID%%"
16
squid_group="%%SQUID_GID%%"
17
squid_gid=100
17
squid_gid=100
18
squid_uid=100
18
squid_uid=100
19
# Try to catch the case where the $squid_user might have been created with an
20
# id greater than or equal 3128. The valid exception is "nobody".
21
nobody_uid=65534
22
nobody_gid=65534
23
squid_oldgid=3128
24
squid_olduid=3128
25
unset wrong_id
26
case $2 in
19
case $2 in
27
PRE-INSTALL)
20
PRE-INSTALL)
28
	echo "===> Pre-installation configuration for ${pkgname}"
21
	echo "===> Pre-installation configuration for ${pkgname}"
29
	if ! pw groupshow ${squid_group} -q >/dev/null ; then
22
	if ! pw groupshow ${squid_group} -q >/dev/null ; then
30
		echo "There is no group '${squid_group}' on this system, so I will try to create it:"
23
		echo "There is no group '${squid_group}' on this system, so I will try to create it (using group id ${squid_gid}):"
31
		if ! pw groupadd ${squid_group} -g ${squid_gid} -q ; then
24
		if ! pw groupadd ${squid_group} -g ${squid_gid} -q ; then
32
			echo "Failed to create group \"${squid_group}\"!" >&2
25
			echo "Failed to create group \"${squid_group}\"!" >&2
33
			echo "Please create it manually." >&2
26
			echo "Please create it manually." >&2
Lines 37-52 Link Here
37
		fi
30
		fi
38
	else
31
	else
39
		echo "I will use the existing group '${squid_group}':"
32
		echo "I will use the existing group '${squid_group}':"
40
		current_gid=`pw groupshow ${squid_group}|cut -f 3 -d :`
41
		if [ ${current_gid} -ge ${squid_oldgid} \
42
		    -a ${current_gid} -ne ${nobody_gid} ]; then
43
			wrong_id=1
44
		fi	
45
	fi
33
	fi
46
	pw groupshow ${squid_group}
34
	pw groupshow ${squid_group}
47
35
48
	if ! pw usershow ${squid_user} -q >/dev/null ; then
36
	if ! pw usershow ${squid_user} -q >/dev/null ; then
49
		echo "There is no account '${squid_user}' on this system, so I will try to create it:"
37
		echo "There is no account '${squid_user}' on this system, so I will try to create it (using user id ${squid_uid}):"
50
		if ! pw useradd -q -n ${squid_user} \
38
		if ! pw useradd -q -n ${squid_user} \
51
		    -u ${squid_uid} -g ${squid_group} \
39
		    -u ${squid_uid} -g ${squid_group} \
52
	  	    -c "squid caching-proxy pseudo user" \
40
	  	    -c "squid caching-proxy pseudo user" \
Lines 60-112 Link Here
60
		fi
48
		fi
61
	else
49
	else
62
		echo "I will use the existing user '${squid_user}':"
50
		echo "I will use the existing user '${squid_user}':"
63
		current_uid=`id -u ${squid_user}`
64
		if [ ${current_uid} -ge ${squid_olduid} \
65
		    -a ${current_uid} -ne ${nobody_uid} ];
66
		then
67
			wrong_id=1
68
		fi
69
	fi
51
	fi
70
	pw usershow ${squid_user}
52
	pw usershow ${squid_user}
71
	if [ "${wrong_id}" ]; then
72
		echo ""
73
		echo " * NOTICE *"
74
		echo ""
75
		echo "The squid pseudo-user's uid and/or gid have been found"
76
		echo "to be greater than or equal 3128."
77
		echo ""
78
		echo "This is not a problem as such, but violates the FreeBSD"
79
		echo "ports' principle that a ports must not claim a uid greater"
80
		echo "than 999."
81
		echo ""
82
		echo "Since version 2.5.4_11, the squid user is thus created"
83
		echo "with an id of ${squid_uid}:${squid_gid} while earlier versions of this"
84
		echo "port used the first unused uid/gid greater than or"
85
		echo "equal 3128."
86
		echo ""
87
		echo "If you want to change the existing squid user's id, run"
88
		echo "'make changeuser' after the installation has completed."
89
		echo "If you installed this port via a package, issue the"
90
		echo "following commands as root:"
91
		echo ""
92
		echo "pw userdel -u ${current_uid}"
93
		echo "pw groupadd -n ${squid_group} -g ${squid_gid}"
94
		echo "pw useradd -n ${squid_user} -u ${squid_uid} \\"
95
		echo "    -c \"squid caching-proxy pseudo user\" \\"
96
		echo "    -g ${squid_group} -d ${squid_base} -s /sbin/nologin \\"
97
		echo "    -h -"
98
		echo "find -H ${PKG_PREFIX} -user ${current_uid} -exec chown ${squid_user} {} \\;"
99
		echo "find -H ${PKG_PREFIX} -group ${current_gid} -exec chgrp ${squid_group} {} \\;"
100
		echo ""
101
		echo "In case you have installed third party software for squid"
102
		echo "like squidGuard, you should additionally run:"
103
		echo "find -H /var -user ${current_uid} -exec chown ${squid_user} {} \\;"
104
		echo "find -H /var -group ${current_gid} -exec chgrp ${squid_group} {} \\;"
105
		echo ""
106
		if [ -z "${PACKAGE_BUILDING}" -a -z "${BATCH}" ]; then
107
			sleep 30
108
		fi
109
	fi
110
	for dir in cache logs; do
53
	for dir in cache logs; do
111
	if [ ! -d ${squid_base}/${dir} ]; then
54
	if [ ! -d ${squid_base}/${dir} ]; then
112
		echo "Creating ${squid_base}/${dir}..."
55
		echo "Creating ${squid_base}/${dir}..."
(-)files/squid.in (+52 lines)
Line 0 Link Here
1
#!/bin/sh
2
#
3
# $FreeBSD$
4
#
5
# PROVIDE: squid
6
# REQUIRE: LOGIN
7
# KEYWORD: shutdown
8
# 
9
# Note:
10
# Set "squid_enable=yes" in either /etc/rc.conf, /etc/rc.conf.local or
11
# /etc/rc.conf.d/squid to make this script actually do something. There
12
# you can also set squid_chdir, squid_user, and squid_flags.
13
#
14
# Please see squid(8), rc.conf(5) and rc(8) for further details.
15
#
16
17
squid_stop() {
18
	${command} -k shutdown
19
	run_rc_command poll
20
}
21
22
. %%RC_SUBR%%
23
24
name=squid
25
rcvar=${name}_enable
26
27
command=%%PREFIX%%/sbin/squid
28
extra_commands=reload
29
reload_cmd="${command} -k reconfigure"
30
stop_cmd="squid_stop"
31
32
load_rc_config ${name}
33
34
squid_chdir=${squid_chdir:-%%PREFIX%%/squid/logs}
35
squid_enable=${squid_enable:-"NO"}
36
squid_flags=${squid_flags-"-D"}
37
squid_user=${squid_user:-%%SQUID_UID%%}
38
default_config=%%PREFIX%%/etc/squid/squid.conf
39
40
required_dirs=${squid_chdir}
41
42
# squid(8) will not start if ${default_config} is not present so try
43
# to catch that beforehand via ${required_files} rather than make
44
# squid(8) crash.
45
# If you remove the default configuration file make sure to add
46
# '-f /path/to/your/squid.conf' to squid_flags
47
48
if [ -z "${squid_flags}" ]; then
49
	required_files=${default_config}
50
fi
51
52
run_rc_command "$1"
(-)files/patch-tools-Makefile.in (+11 lines)
Line 0 Link Here
1
--- tools/Makefile.in.orig	Sun May 14 18:30:04 2006
2
+++ tools/Makefile.in	Sun May 14 18:31:02 2006
3
@@ -297,7 +297,7 @@
4
 EXTRA_DIST = \
5
 	cachemgr.conf
6
 
7
-DEFAULT_CACHEMGR_CONFIG = $(sysconfdir)/cachemgr.conf
8
+DEFAULT_CACHEMGR_CONFIG = $(sysconfdir)/cachemgr.conf.default
9
 
10
 # Don't automatically uninstall config files
11
 #	@if test -f $(DESTDIR)$(DEFAULT_CONFIG_FILE) ; then \
(-)files/squid.sh.in (-87 lines)
Lines 1-87 Link Here
1
#!/bin/sh
2
#
3
# $FreeBSD: ports/www/squid/files/squid.sh.in,v 1.1 2006/03/18 17:11:13 pav Exp $
4
#
5
# --begin rcng
6
# PROVIDE: squid
7
# REQUIRE: LOGIN
8
# KEYWORD: shutdown
9
# 
10
# Note:
11
# Set "squid_enable=yes" in either /etc/rc.conf, /etc/rc.conf.local or
12
# /etc/rc.conf.d/squid to make this script actually do something. There
13
# you can also set squid_chdir, squid_user, and squid_flags.
14
#
15
# Please see squid(8), rc.conf(5) and rc(8) for further details.
16
#
17
# --end rcng
18
19
name=squid
20
command=%%PREFIX%%/sbin/squid
21
# --begin rcng
22
extra_commands=reload
23
reload_cmd="${command} -k reconfigure"
24
# --end rcng
25
stop_cmd="squid_stop"
26
squid_chdir=${squid_chdir:-%%PREFIX%%/squid/logs}
27
# --begin rcng
28
squid_enable=${squid_enable:-"NO"}
29
# --end rcng
30
squid_flags=${squid_flags-"-D"}
31
squid_user=${squid_user:-%%SQUID_UID%%}
32
default_config=%%PREFIX%%/etc/squid/squid.conf
33
34
# --begin rcold
35
squid_stop() {
36
	echo -n " ${name}"
37
	${command} -k shutdown
38
	while ps -xcU ${squid_user} | grep -q squid; do
39
		sleep 2
40
	done
41
}
42
43
# --end rcold
44
# --begin rcng
45
squid_stop() {
46
	${command} -k shutdown
47
	run_rc_command poll
48
}
49
50
. %%RC_SUBR%%
51
rcvar=`set_rcvar`
52
load_rc_config ${name}
53
54
# squid(8) will not start if ${default_config} is not present so try
55
# to catch that beforehand via ${required_files} rather than make
56
# squid(8) crash.
57
# If you remove the default configuration file make sure to add
58
# '-f /path/to/your/squid.conf' to squid_flags
59
60
if [ -z "${squid_flags}" ]; then
61
	required_files=${default_config}
62
fi
63
required_dirs=${squid_chdir}
64
run_rc_command "$1"
65
# --end rcng
66
# --begin rcold
67
case $1 in
68
start)
69
	if [ -x "${command}" -a \
70
		\( -f "${default_config}" -o "${squid_flags}" \) ]; then
71
		echo -n " ${name}"
72
		(cd ${squid_chdir} && exec su -fm ${squid_user} -c \
73
			"${command} ${squid_flags}")
74
	fi
75
	;;
76
stop)
77
	if [ -x "${command}" ]; then
78
		${stop_cmd}
79
	fi
80
	;;
81
*)
82
	echo "usage: ${0##*/} {start|stop}" >&2
83
	exit 64
84
	;;
85
esac
86
exit 0
87
# --end rcold
(-)files/follow_xff-configure.patch (-65 lines)
Lines 1-65 Link Here
1
!Simulate the autotools bootstrap of the follow-x-forwarded-for patchset.
2
!
3
!Beware that all line number informations in configure.log greater
4
!than 2972 are offset by at least -29 (correcting all line numbers would have
5
!bloated the patch by 92kB!)
6
--- include/autoconf.h.in.orig	Sat Jan 18 02:46:11 2003
7
+++ include/autoconf.h.in	Thu Jun 24 13:19:07 2004
8
@@ -291,6 +291,12 @@
9
 #define USE_IDENT 1
10
 
11
 /*
12
+ * Compile in support for following X-Forwarded-For headers?
13
+ * Enabled by default.
14
+ */
15
+#define FOLLOW_X_FORWARDED_FOR 1
16
+
17
+/*
18
  * If your system has statvfs(), and if it actually works!
19
  */
20
 #undef HAVE_STATVFS
21
--- configure.orig	Thu Sep 22 10:16:26 2005
22
+++ configure	Thu Sep 22 17:29:01 2005
23
@@ -249,6 +249,12 @@
24
                           if you build as another user who is not privileged
25
                           to use the number of filedescriptors you want the
26
                           resulting binary to support"
27
+ac_help="$ac_help
28
+  --enable-follow-x-forwarded-for
29
+                          Enable support for following the X-Forwarded-For
30
+                          HTTP header to try to find the IP address of the
31
+                          original or indirect client when a request has
32
+                          been forwarded through other proxies."
33
 
34
 # Initialize some variables set by options.
35
 # The variables have the same names as the options, with
36
@@ -3255,6 +3261,29 @@
37
 
38
 fi
39
 
40
+
41
+follow_xff=1
42
+# Check whether --enable-follow-x-forwarded-for or --disable-follow-x-forwarded-for was given.
43
+if test "${enable_follow_x_forwarded_for+set}" = set; then
44
+  enableval="$enable_follow_x_forwarded_for"
45
+   if test "$enableval" = "yes" ; then
46
+    echo "follow X-Forwarded-For enabled"
47
+    follow_xff=1
48
+  fi
49
+
50
+fi
51
+
52
+if test $follow_xff = 1; then
53
+    cat >> confdefs.h <<\EOF
54
+#define FOLLOW_X_FORWARDED_FOR 1
55
+EOF
56
+
57
+else
58
+    cat >> confdefs.h <<\EOF
59
+#define FOLLOW_X_FORWARDED_FOR 0
60
+EOF
61
+
62
+fi
63
 
64
 # Force some compilers to use ANSI features
65
 #
(-)files/icap-2.5-core.patch (-7137 lines)
Lines 1-7137 Link Here
1
Patch 1 of 2 to integrate the icap-2_5 branch into the FreeBSD squid port.
2
3
Created by Thomas-Martin Seck <tmseck@netcologne.de>.
4
5
This patch only contains the parts of the original patchset that
6
actually implement the ICAP client functionality. The updates to
7
the build infrastructure are omitted to avoid the need to run an
8
autotools bootstrap.  Instead, we simulate said bootstrapping with
9
a second patch, icap-2.5-bootstrap.patch.
10
11
The patchset was pulled from the project's CVS repository
12
at cvs.devel.squid-cache.org using
13
14
cvs diff -u -b -N -kk -rs2_5 -ricap-2_5
15
16
See also
17
<http://devel.squid-cache.org/cgi-bin/diff2/icap-2_5.patch?s2_5>
18
for the "official" auto-generated patchset.
19
20
See http://devel.squid-cache.org/icap/ for further information
21
about the ICAP client project.
22
23
Patch last updated: 2006-06-01
24
25
Index: errors/Azerbaijani/ERR_ICAP_FAILURE
26
===================================================================
27
RCS file: errors/Azerbaijani/ERR_ICAP_FAILURE
28
diff -N errors/Azerbaijani/ERR_ICAP_FAILURE
29
--- /dev/null	1 Jan 1970 00:00:00 -0000
30
+++ errors/Azerbaijani/ERR_ICAP_FAILURE	8 Dec 2003 12:30:56 -0000	1.1.2.1
31
@@ -0,0 +1,31 @@
32
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
33
+<HTML><HEAD>
34
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
35
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
36
+</HEAD><BODY>
37
+<H1>ERROR</H1>
38
+<H2>The requested URL could not be retrieved</H2>
39
+<HR noshade size="1px">
40
+<P>
41
+While attempting to retrieve the URL:
42
+<A HREF="%U">%U</A>
43
+<P>
44
+the following error was encountered:
45
+<UL>
46
+<LI>
47
+<STRONG>
48
+ICAP protocol error.
49
+</STRONG>
50
+</UL>
51
+
52
+<P>
53
+<P>
54
+Some aspect of the ICAP communication failed. Possible problems:
55
+<UL>
56
+<LI>ICAP server is not reachable.
57
+<LI>Illegal response from ICAP server.
58
+</UL>
59
+</P>
60
+
61
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
62
+
63
Index: errors/Bulgarian/ERR_ICAP_FAILURE
64
===================================================================
65
RCS file: errors/Bulgarian/ERR_ICAP_FAILURE
66
diff -N errors/Bulgarian/ERR_ICAP_FAILURE
67
--- /dev/null	1 Jan 1970 00:00:00 -0000
68
+++ errors/Bulgarian/ERR_ICAP_FAILURE	8 Dec 2003 12:30:56 -0000	1.1.2.1
69
@@ -0,0 +1,31 @@
70
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
71
+<HTML><HEAD>
72
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
73
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
74
+</HEAD><BODY>
75
+<H1>ERROR</H1>
76
+<H2>The requested URL could not be retrieved</H2>
77
+<HR noshade size="1px">
78
+<P>
79
+While attempting to retrieve the URL:
80
+<A HREF="%U">%U</A>
81
+<P>
82
+the following error was encountered:
83
+<UL>
84
+<LI>
85
+<STRONG>
86
+ICAP protocol error.
87
+</STRONG>
88
+</UL>
89
+
90
+<P>
91
+<P>
92
+Some aspect of the ICAP communication failed. Possible problems:
93
+<UL>
94
+<LI>ICAP server is not reachable.
95
+<LI>Illegal response from ICAP server.
96
+</UL>
97
+</P>
98
+
99
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
100
+
101
Index: errors/Catalan/ERR_ICAP_FAILURE
102
===================================================================
103
RCS file: errors/Catalan/ERR_ICAP_FAILURE
104
diff -N errors/Catalan/ERR_ICAP_FAILURE
105
--- /dev/null	1 Jan 1970 00:00:00 -0000
106
+++ errors/Catalan/ERR_ICAP_FAILURE	8 Dec 2003 12:30:57 -0000	1.1.2.1
107
@@ -0,0 +1,31 @@
108
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
109
+<HTML><HEAD>
110
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
111
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
112
+</HEAD><BODY>
113
+<H1>ERROR</H1>
114
+<H2>The requested URL could not be retrieved</H2>
115
+<HR noshade size="1px">
116
+<P>
117
+While attempting to retrieve the URL:
118
+<A HREF="%U">%U</A>
119
+<P>
120
+the following error was encountered:
121
+<UL>
122
+<LI>
123
+<STRONG>
124
+ICAP protocol error.
125
+</STRONG>
126
+</UL>
127
+
128
+<P>
129
+<P>
130
+Some aspect of the ICAP communication failed. Possible problems:
131
+<UL>
132
+<LI>ICAP server is not reachable.
133
+<LI>Illegal response from ICAP server.
134
+</UL>
135
+</P>
136
+
137
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
138
+
139
Index: errors/Czech/ERR_ICAP_FAILURE
140
===================================================================
141
RCS file: errors/Czech/ERR_ICAP_FAILURE
142
diff -N errors/Czech/ERR_ICAP_FAILURE
143
--- /dev/null	1 Jan 1970 00:00:00 -0000
144
+++ errors/Czech/ERR_ICAP_FAILURE	8 Dec 2003 12:30:57 -0000	1.1.2.1
145
@@ -0,0 +1,31 @@
146
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
147
+<HTML><HEAD>
148
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
149
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
150
+</HEAD><BODY>
151
+<H1>ERROR</H1>
152
+<H2>The requested URL could not be retrieved</H2>
153
+<HR noshade size="1px">
154
+<P>
155
+While attempting to retrieve the URL:
156
+<A HREF="%U">%U</A>
157
+<P>
158
+the following error was encountered:
159
+<UL>
160
+<LI>
161
+<STRONG>
162
+ICAP protocol error.
163
+</STRONG>
164
+</UL>
165
+
166
+<P>
167
+<P>
168
+Some aspect of the ICAP communication failed. Possible problems:
169
+<UL>
170
+<LI>ICAP server is not reachable.
171
+<LI>Illegal response from ICAP server.
172
+</UL>
173
+</P>
174
+
175
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
176
+
177
Index: errors/Danish/ERR_ICAP_FAILURE
178
===================================================================
179
RCS file: errors/Danish/ERR_ICAP_FAILURE
180
diff -N errors/Danish/ERR_ICAP_FAILURE
181
--- /dev/null	1 Jan 1970 00:00:00 -0000
182
+++ errors/Danish/ERR_ICAP_FAILURE	8 Dec 2003 12:30:57 -0000	1.1.2.1
183
@@ -0,0 +1,31 @@
184
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
185
+<HTML><HEAD>
186
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
187
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
188
+</HEAD><BODY>
189
+<H1>ERROR</H1>
190
+<H2>The requested URL could not be retrieved</H2>
191
+<HR noshade size="1px">
192
+<P>
193
+While attempting to retrieve the URL:
194
+<A HREF="%U">%U</A>
195
+<P>
196
+the following error was encountered:
197
+<UL>
198
+<LI>
199
+<STRONG>
200
+ICAP protocol error.
201
+</STRONG>
202
+</UL>
203
+
204
+<P>
205
+<P>
206
+Some aspect of the ICAP communication failed. Possible problems:
207
+<UL>
208
+<LI>ICAP server is not reachable.
209
+<LI>Illegal response from ICAP server.
210
+</UL>
211
+</P>
212
+
213
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
214
+
215
Index: errors/Dutch/ERR_ICAP_FAILURE
216
===================================================================
217
RCS file: errors/Dutch/ERR_ICAP_FAILURE
218
diff -N errors/Dutch/ERR_ICAP_FAILURE
219
--- /dev/null	1 Jan 1970 00:00:00 -0000
220
+++ errors/Dutch/ERR_ICAP_FAILURE	8 Dec 2003 12:30:57 -0000	1.1.2.1
221
@@ -0,0 +1,31 @@
222
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
223
+<HTML><HEAD>
224
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
225
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
226
+</HEAD><BODY>
227
+<H1>ERROR</H1>
228
+<H2>The requested URL could not be retrieved</H2>
229
+<HR noshade size="1px">
230
+<P>
231
+While attempting to retrieve the URL:
232
+<A HREF="%U">%U</A>
233
+<P>
234
+the following error was encountered:
235
+<UL>
236
+<LI>
237
+<STRONG>
238
+ICAP protocol error.
239
+</STRONG>
240
+</UL>
241
+
242
+<P>
243
+<P>
244
+Some aspect of the ICAP communication failed. Possible problems:
245
+<UL>
246
+<LI>ICAP server is not reachable.
247
+<LI>Illegal response from ICAP server.
248
+</UL>
249
+</P>
250
+
251
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
252
+
253
Index: errors/English/ERR_ICAP_FAILURE
254
===================================================================
255
RCS file: errors/English/ERR_ICAP_FAILURE
256
diff -N errors/English/ERR_ICAP_FAILURE
257
--- /dev/null	1 Jan 1970 00:00:00 -0000
258
+++ errors/English/ERR_ICAP_FAILURE	8 Dec 2003 12:30:57 -0000	1.1.2.2
259
@@ -0,0 +1,31 @@
260
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
261
+<HTML><HEAD>
262
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
263
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
264
+</HEAD><BODY>
265
+<H1>ERROR</H1>
266
+<H2>The requested URL could not be retrieved</H2>
267
+<HR noshade size="1px">
268
+<P>
269
+While attempting to retrieve the URL:
270
+<A HREF="%U">%U</A>
271
+<P>
272
+the following error was encountered:
273
+<UL>
274
+<LI>
275
+<STRONG>
276
+ICAP protocol error.
277
+</STRONG>
278
+</UL>
279
+
280
+<P>
281
+<P>
282
+Some aspect of the ICAP communication failed. Possible problems:
283
+<UL>
284
+<LI>ICAP server is not reachable.
285
+<LI>Illegal response from ICAP server.
286
+</UL>
287
+</P>
288
+
289
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
290
+
291
Index: errors/Estonian/ERR_ICAP_FAILURE
292
===================================================================
293
RCS file: errors/Estonian/ERR_ICAP_FAILURE
294
diff -N errors/Estonian/ERR_ICAP_FAILURE
295
--- /dev/null	1 Jan 1970 00:00:00 -0000
296
+++ errors/Estonian/ERR_ICAP_FAILURE	8 Dec 2003 12:30:58 -0000	1.1.2.1
297
@@ -0,0 +1,31 @@
298
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
299
+<HTML><HEAD>
300
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
301
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
302
+</HEAD><BODY>
303
+<H1>ERROR</H1>
304
+<H2>The requested URL could not be retrieved</H2>
305
+<HR noshade size="1px">
306
+<P>
307
+While attempting to retrieve the URL:
308
+<A HREF="%U">%U</A>
309
+<P>
310
+the following error was encountered:
311
+<UL>
312
+<LI>
313
+<STRONG>
314
+ICAP protocol error.
315
+</STRONG>
316
+</UL>
317
+
318
+<P>
319
+<P>
320
+Some aspect of the ICAP communication failed. Possible problems:
321
+<UL>
322
+<LI>ICAP server is not reachable.
323
+<LI>Illegal response from ICAP server.
324
+</UL>
325
+</P>
326
+
327
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
328
+
329
Index: errors/Finnish/ERR_ICAP_FAILURE
330
===================================================================
331
RCS file: errors/Finnish/ERR_ICAP_FAILURE
332
diff -N errors/Finnish/ERR_ICAP_FAILURE
333
--- /dev/null	1 Jan 1970 00:00:00 -0000
334
+++ errors/Finnish/ERR_ICAP_FAILURE	8 Dec 2003 12:30:58 -0000	1.1.2.1
335
@@ -0,0 +1,31 @@
336
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
337
+<HTML><HEAD>
338
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
339
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
340
+</HEAD><BODY>
341
+<H1>ERROR</H1>
342
+<H2>The requested URL could not be retrieved</H2>
343
+<HR noshade size="1px">
344
+<P>
345
+While attempting to retrieve the URL:
346
+<A HREF="%U">%U</A>
347
+<P>
348
+the following error was encountered:
349
+<UL>
350
+<LI>
351
+<STRONG>
352
+ICAP protocol error.
353
+</STRONG>
354
+</UL>
355
+
356
+<P>
357
+<P>
358
+Some aspect of the ICAP communication failed. Possible problems:
359
+<UL>
360
+<LI>ICAP server is not reachable.
361
+<LI>Illegal response from ICAP server.
362
+</UL>
363
+</P>
364
+
365
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
366
+
367
Index: errors/French/ERR_ICAP_FAILURE
368
===================================================================
369
RCS file: errors/French/ERR_ICAP_FAILURE
370
diff -N errors/French/ERR_ICAP_FAILURE
371
--- /dev/null	1 Jan 1970 00:00:00 -0000
372
+++ errors/French/ERR_ICAP_FAILURE	8 Dec 2003 12:30:58 -0000	1.1.2.1
373
@@ -0,0 +1,31 @@
374
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
375
+<HTML><HEAD>
376
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
377
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
378
+</HEAD><BODY>
379
+<H1>ERROR</H1>
380
+<H2>The requested URL could not be retrieved</H2>
381
+<HR noshade size="1px">
382
+<P>
383
+While attempting to retrieve the URL:
384
+<A HREF="%U">%U</A>
385
+<P>
386
+the following error was encountered:
387
+<UL>
388
+<LI>
389
+<STRONG>
390
+ICAP protocol error.
391
+</STRONG>
392
+</UL>
393
+
394
+<P>
395
+<P>
396
+Some aspect of the ICAP communication failed. Possible problems:
397
+<UL>
398
+<LI>ICAP server is not reachable.
399
+<LI>Illegal response from ICAP server.
400
+</UL>
401
+</P>
402
+
403
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
404
+
405
Index: errors/German/ERR_ICAP_FAILURE
406
===================================================================
407
RCS file: errors/German/ERR_ICAP_FAILURE
408
diff -N errors/German/ERR_ICAP_FAILURE
409
--- /dev/null	1 Jan 1970 00:00:00 -0000
410
+++ errors/German/ERR_ICAP_FAILURE	23 Mar 2004 08:20:05 -0000	1.1.2.2
411
@@ -0,0 +1,33 @@
412
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
413
+<HTML><HEAD>
414
+<TITLE>FEHLER: Der angeforderte URL konnte nicht geholt werden</TITLE>
415
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
416
+</HEAD><BODY>
417
+<H1>FEHLER</H1>
418
+<H2>Der angeforderte URL konnte nicht geholt werden</H2>
419
+<HR noshade size="1px">
420
+<P>
421
+W&auml;hrend des Versuches, den URL<BR>
422
+<A HREF="%U">%U</A>
423
+
424
+<BR>
425
+zu laden, trat der folgende Fehler auf:
426
+<UL>
427
+<LI>
428
+<STRONG>
429
+ICAP-Protokollfehler
430
+</STRONG>
431
+</UL>
432
+
433
+<P>
434
+<P>
435
+Es trat ein Problem bei der ICAP-Kommunikation auf. M&ouml;gliche Gr&uuml;nde:
436
+<UL>
437
+<LI>Nicht erreichbarer ICAP-Server
438
+<LI>Ung&uuml;ltige Antwort vom ICAP-Server
439
+
440
+</UL>
441
+</P>
442
+
443
+<P>Ihr Cache Administrator ist <A HREF="mailto:%w">%w</A>. 
444
+
445
Index: errors/Greek/ERR_ICAP_FAILURE
446
===================================================================
447
RCS file: errors/Greek/ERR_ICAP_FAILURE
448
diff -N errors/Greek/ERR_ICAP_FAILURE
449
--- /dev/null	1 Jan 1970 00:00:00 -0000
450
+++ errors/Greek/ERR_ICAP_FAILURE	24 Sep 2005 10:31:00 -0000	1.1.2.1
451
@@ -0,0 +1,31 @@
452
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
453
+<HTML><HEAD>
454
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
455
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
456
+</HEAD><BODY>
457
+<H1>ERROR</H1>
458
+<H2>The requested URL could not be retrieved</H2>
459
+<HR noshade size="1px">
460
+<P>
461
+While attempting to retrieve the URL:
462
+<A HREF="%U">%U</A>
463
+<P>
464
+the following error was encountered:
465
+<UL>
466
+<LI>
467
+<STRONG>
468
+ICAP protocol error.
469
+</STRONG>
470
+</UL>
471
+
472
+<P>
473
+<P>
474
+Some aspect of the ICAP communication failed. Possible problems:
475
+<UL>
476
+<LI>ICAP server is not reachable.
477
+<LI>Illegal response from ICAP server.
478
+</UL>
479
+</P>
480
+
481
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
482
+
483
Index: errors/Hebrew/ERR_ICAP_FAILURE
484
===================================================================
485
RCS file: errors/Hebrew/ERR_ICAP_FAILURE
486
diff -N errors/Hebrew/ERR_ICAP_FAILURE
487
--- /dev/null	1 Jan 1970 00:00:00 -0000
488
+++ errors/Hebrew/ERR_ICAP_FAILURE	8 Dec 2003 12:30:59 -0000	1.1.2.1
489
@@ -0,0 +1,31 @@
490
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
491
+<HTML><HEAD>
492
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
493
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
494
+</HEAD><BODY>
495
+<H1>ERROR</H1>
496
+<H2>The requested URL could not be retrieved</H2>
497
+<HR noshade size="1px">
498
+<P>
499
+While attempting to retrieve the URL:
500
+<A HREF="%U">%U</A>
501
+<P>
502
+the following error was encountered:
503
+<UL>
504
+<LI>
505
+<STRONG>
506
+ICAP protocol error.
507
+</STRONG>
508
+</UL>
509
+
510
+<P>
511
+<P>
512
+Some aspect of the ICAP communication failed. Possible problems:
513
+<UL>
514
+<LI>ICAP server is not reachable.
515
+<LI>Illegal response from ICAP server.
516
+</UL>
517
+</P>
518
+
519
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
520
+
521
Index: errors/Hungarian/ERR_ICAP_FAILURE
522
===================================================================
523
RCS file: errors/Hungarian/ERR_ICAP_FAILURE
524
diff -N errors/Hungarian/ERR_ICAP_FAILURE
525
--- /dev/null	1 Jan 1970 00:00:00 -0000
526
+++ errors/Hungarian/ERR_ICAP_FAILURE	8 Dec 2003 12:30:59 -0000	1.1.2.1
527
@@ -0,0 +1,31 @@
528
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
529
+<HTML><HEAD>
530
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
531
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
532
+</HEAD><BODY>
533
+<H1>ERROR</H1>
534
+<H2>The requested URL could not be retrieved</H2>
535
+<HR noshade size="1px">
536
+<P>
537
+While attempting to retrieve the URL:
538
+<A HREF="%U">%U</A>
539
+<P>
540
+the following error was encountered:
541
+<UL>
542
+<LI>
543
+<STRONG>
544
+ICAP protocol error.
545
+</STRONG>
546
+</UL>
547
+
548
+<P>
549
+<P>
550
+Some aspect of the ICAP communication failed. Possible problems:
551
+<UL>
552
+<LI>ICAP server is not reachable.
553
+<LI>Illegal response from ICAP server.
554
+</UL>
555
+</P>
556
+
557
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
558
+
559
Index: errors/Italian/ERR_ICAP_FAILURE
560
===================================================================
561
RCS file: errors/Italian/ERR_ICAP_FAILURE
562
diff -N errors/Italian/ERR_ICAP_FAILURE
563
--- /dev/null	1 Jan 1970 00:00:00 -0000
564
+++ errors/Italian/ERR_ICAP_FAILURE	8 Dec 2003 12:31:00 -0000	1.1.2.1
565
@@ -0,0 +1,31 @@
566
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
567
+<HTML><HEAD>
568
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
569
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
570
+</HEAD><BODY>
571
+<H1>ERROR</H1>
572
+<H2>The requested URL could not be retrieved</H2>
573
+<HR noshade size="1px">
574
+<P>
575
+While attempting to retrieve the URL:
576
+<A HREF="%U">%U</A>
577
+<P>
578
+the following error was encountered:
579
+<UL>
580
+<LI>
581
+<STRONG>
582
+ICAP protocol error.
583
+</STRONG>
584
+</UL>
585
+
586
+<P>
587
+<P>
588
+Some aspect of the ICAP communication failed. Possible problems:
589
+<UL>
590
+<LI>ICAP server is not reachable.
591
+<LI>Illegal response from ICAP server.
592
+</UL>
593
+</P>
594
+
595
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
596
+
597
Index: errors/Japanese/ERR_ICAP_FAILURE
598
===================================================================
599
RCS file: errors/Japanese/ERR_ICAP_FAILURE
600
diff -N errors/Japanese/ERR_ICAP_FAILURE
601
--- /dev/null	1 Jan 1970 00:00:00 -0000
602
+++ errors/Japanese/ERR_ICAP_FAILURE	8 Dec 2003 12:31:00 -0000	1.1.2.1
603
@@ -0,0 +1,31 @@
604
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
605
+<HTML><HEAD>
606
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
607
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
608
+</HEAD><BODY>
609
+<H1>ERROR</H1>
610
+<H2>The requested URL could not be retrieved</H2>
611
+<HR noshade size="1px">
612
+<P>
613
+While attempting to retrieve the URL:
614
+<A HREF="%U">%U</A>
615
+<P>
616
+the following error was encountered:
617
+<UL>
618
+<LI>
619
+<STRONG>
620
+ICAP protocol error.
621
+</STRONG>
622
+</UL>
623
+
624
+<P>
625
+<P>
626
+Some aspect of the ICAP communication failed. Possible problems:
627
+<UL>
628
+<LI>ICAP server is not reachable.
629
+<LI>Illegal response from ICAP server.
630
+</UL>
631
+</P>
632
+
633
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
634
+
635
Index: errors/Korean/ERR_ICAP_FAILURE
636
===================================================================
637
RCS file: errors/Korean/ERR_ICAP_FAILURE
638
diff -N errors/Korean/ERR_ICAP_FAILURE
639
--- /dev/null	1 Jan 1970 00:00:00 -0000
640
+++ errors/Korean/ERR_ICAP_FAILURE	8 Dec 2003 12:31:00 -0000	1.1.2.1
641
@@ -0,0 +1,31 @@
642
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
643
+<HTML><HEAD>
644
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
645
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
646
+</HEAD><BODY>
647
+<H1>ERROR</H1>
648
+<H2>The requested URL could not be retrieved</H2>
649
+<HR noshade size="1px">
650
+<P>
651
+While attempting to retrieve the URL:
652
+<A HREF="%U">%U</A>
653
+<P>
654
+the following error was encountered:
655
+<UL>
656
+<LI>
657
+<STRONG>
658
+ICAP protocol error.
659
+</STRONG>
660
+</UL>
661
+
662
+<P>
663
+<P>
664
+Some aspect of the ICAP communication failed. Possible problems:
665
+<UL>
666
+<LI>ICAP server is not reachable.
667
+<LI>Illegal response from ICAP server.
668
+</UL>
669
+</P>
670
+
671
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
672
+
673
Index: errors/Lithuanian/ERR_ICAP_FAILURE
674
===================================================================
675
RCS file: errors/Lithuanian/ERR_ICAP_FAILURE
676
diff -N errors/Lithuanian/ERR_ICAP_FAILURE
677
--- /dev/null	1 Jan 1970 00:00:00 -0000
678
+++ errors/Lithuanian/ERR_ICAP_FAILURE	8 Dec 2003 12:31:00 -0000	1.1.2.1
679
@@ -0,0 +1,31 @@
680
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
681
+<HTML><HEAD>
682
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
683
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
684
+</HEAD><BODY>
685
+<H1>ERROR</H1>
686
+<H2>The requested URL could not be retrieved</H2>
687
+<HR noshade size="1px">
688
+<P>
689
+While attempting to retrieve the URL:
690
+<A HREF="%U">%U</A>
691
+<P>
692
+the following error was encountered:
693
+<UL>
694
+<LI>
695
+<STRONG>
696
+ICAP protocol error.
697
+</STRONG>
698
+</UL>
699
+
700
+<P>
701
+<P>
702
+Some aspect of the ICAP communication failed. Possible problems:
703
+<UL>
704
+<LI>ICAP server is not reachable.
705
+<LI>Illegal response from ICAP server.
706
+</UL>
707
+</P>
708
+
709
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
710
+
711
Index: errors/Polish/ERR_ICAP_FAILURE
712
===================================================================
713
RCS file: errors/Polish/ERR_ICAP_FAILURE
714
diff -N errors/Polish/ERR_ICAP_FAILURE
715
--- /dev/null	1 Jan 1970 00:00:00 -0000
716
+++ errors/Polish/ERR_ICAP_FAILURE	8 Dec 2003 12:31:00 -0000	1.1.2.1
717
@@ -0,0 +1,31 @@
718
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
719
+<HTML><HEAD>
720
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
721
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
722
+</HEAD><BODY>
723
+<H1>ERROR</H1>
724
+<H2>The requested URL could not be retrieved</H2>
725
+<HR noshade size="1px">
726
+<P>
727
+While attempting to retrieve the URL:
728
+<A HREF="%U">%U</A>
729
+<P>
730
+the following error was encountered:
731
+<UL>
732
+<LI>
733
+<STRONG>
734
+ICAP protocol error.
735
+</STRONG>
736
+</UL>
737
+
738
+<P>
739
+<P>
740
+Some aspect of the ICAP communication failed. Possible problems:
741
+<UL>
742
+<LI>ICAP server is not reachable.
743
+<LI>Illegal response from ICAP server.
744
+</UL>
745
+</P>
746
+
747
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
748
+
749
Index: errors/Portuguese/ERR_ICAP_FAILURE
750
===================================================================
751
RCS file: errors/Portuguese/ERR_ICAP_FAILURE
752
diff -N errors/Portuguese/ERR_ICAP_FAILURE
753
--- /dev/null	1 Jan 1970 00:00:00 -0000
754
+++ errors/Portuguese/ERR_ICAP_FAILURE	8 Dec 2003 12:31:01 -0000	1.1.2.1
755
@@ -0,0 +1,31 @@
756
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
757
+<HTML><HEAD>
758
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
759
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
760
+</HEAD><BODY>
761
+<H1>ERROR</H1>
762
+<H2>The requested URL could not be retrieved</H2>
763
+<HR noshade size="1px">
764
+<P>
765
+While attempting to retrieve the URL:
766
+<A HREF="%U">%U</A>
767
+<P>
768
+the following error was encountered:
769
+<UL>
770
+<LI>
771
+<STRONG>
772
+ICAP protocol error.
773
+</STRONG>
774
+</UL>
775
+
776
+<P>
777
+<P>
778
+Some aspect of the ICAP communication failed. Possible problems:
779
+<UL>
780
+<LI>ICAP server is not reachable.
781
+<LI>Illegal response from ICAP server.
782
+</UL>
783
+</P>
784
+
785
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
786
+
787
Index: errors/Romanian/ERR_ICAP_FAILURE
788
===================================================================
789
RCS file: errors/Romanian/ERR_ICAP_FAILURE
790
diff -N errors/Romanian/ERR_ICAP_FAILURE
791
--- /dev/null	1 Jan 1970 00:00:00 -0000
792
+++ errors/Romanian/ERR_ICAP_FAILURE	8 Dec 2003 12:31:01 -0000	1.1.2.1
793
@@ -0,0 +1,31 @@
794
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
795
+<HTML><HEAD>
796
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
797
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
798
+</HEAD><BODY>
799
+<H1>ERROR</H1>
800
+<H2>The requested URL could not be retrieved</H2>
801
+<HR noshade size="1px">
802
+<P>
803
+While attempting to retrieve the URL:
804
+<A HREF="%U">%U</A>
805
+<P>
806
+the following error was encountered:
807
+<UL>
808
+<LI>
809
+<STRONG>
810
+ICAP protocol error.
811
+</STRONG>
812
+</UL>
813
+
814
+<P>
815
+<P>
816
+Some aspect of the ICAP communication failed. Possible problems:
817
+<UL>
818
+<LI>ICAP server is not reachable.
819
+<LI>Illegal response from ICAP server.
820
+</UL>
821
+</P>
822
+
823
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
824
+
825
Index: errors/Russian-1251/ERR_ICAP_FAILURE
826
===================================================================
827
RCS file: errors/Russian-1251/ERR_ICAP_FAILURE
828
diff -N errors/Russian-1251/ERR_ICAP_FAILURE
829
--- /dev/null	1 Jan 1970 00:00:00 -0000
830
+++ errors/Russian-1251/ERR_ICAP_FAILURE	8 Dec 2003 12:31:02 -0000	1.1.2.1
831
@@ -0,0 +1,31 @@
832
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
833
+<HTML><HEAD>
834
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
835
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
836
+</HEAD><BODY>
837
+<H1>ERROR</H1>
838
+<H2>The requested URL could not be retrieved</H2>
839
+<HR noshade size="1px">
840
+<P>
841
+While attempting to retrieve the URL:
842
+<A HREF="%U">%U</A>
843
+<P>
844
+the following error was encountered:
845
+<UL>
846
+<LI>
847
+<STRONG>
848
+ICAP protocol error.
849
+</STRONG>
850
+</UL>
851
+
852
+<P>
853
+<P>
854
+Some aspect of the ICAP communication failed. Possible problems:
855
+<UL>
856
+<LI>ICAP server is not reachable.
857
+<LI>Illegal response from ICAP server.
858
+</UL>
859
+</P>
860
+
861
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
862
+
863
Index: errors/Russian-koi8-r/ERR_ICAP_FAILURE
864
===================================================================
865
RCS file: errors/Russian-koi8-r/ERR_ICAP_FAILURE
866
diff -N errors/Russian-koi8-r/ERR_ICAP_FAILURE
867
--- /dev/null	1 Jan 1970 00:00:00 -0000
868
+++ errors/Russian-koi8-r/ERR_ICAP_FAILURE	8 Dec 2003 12:31:02 -0000	1.1.2.1
869
@@ -0,0 +1,31 @@
870
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
871
+<HTML><HEAD>
872
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
873
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
874
+</HEAD><BODY>
875
+<H1>ERROR</H1>
876
+<H2>The requested URL could not be retrieved</H2>
877
+<HR noshade size="1px">
878
+<P>
879
+While attempting to retrieve the URL:
880
+<A HREF="%U">%U</A>
881
+<P>
882
+the following error was encountered:
883
+<UL>
884
+<LI>
885
+<STRONG>
886
+ICAP protocol error.
887
+</STRONG>
888
+</UL>
889
+
890
+<P>
891
+<P>
892
+Some aspect of the ICAP communication failed. Possible problems:
893
+<UL>
894
+<LI>ICAP server is not reachable.
895
+<LI>Illegal response from ICAP server.
896
+</UL>
897
+</P>
898
+
899
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
900
+
901
Index: errors/Serbian/ERR_ICAP_FAILURE
902
===================================================================
903
RCS file: errors/Serbian/ERR_ICAP_FAILURE
904
diff -N errors/Serbian/ERR_ICAP_FAILURE
905
--- /dev/null	1 Jan 1970 00:00:00 -0000
906
+++ errors/Serbian/ERR_ICAP_FAILURE	8 Dec 2003 12:31:02 -0000	1.1.2.1
907
@@ -0,0 +1,31 @@
908
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
909
+<HTML><HEAD>
910
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
911
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
912
+</HEAD><BODY>
913
+<H1>ERROR</H1>
914
+<H2>The requested URL could not be retrieved</H2>
915
+<HR noshade size="1px">
916
+<P>
917
+While attempting to retrieve the URL:
918
+<A HREF="%U">%U</A>
919
+<P>
920
+the following error was encountered:
921
+<UL>
922
+<LI>
923
+<STRONG>
924
+ICAP protocol error.
925
+</STRONG>
926
+</UL>
927
+
928
+<P>
929
+<P>
930
+Some aspect of the ICAP communication failed. Possible problems:
931
+<UL>
932
+<LI>ICAP server is not reachable.
933
+<LI>Illegal response from ICAP server.
934
+</UL>
935
+</P>
936
+
937
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
938
+
939
Index: errors/Simplify_Chinese/ERR_ICAP_FAILURE
940
===================================================================
941
RCS file: errors/Simplify_Chinese/ERR_ICAP_FAILURE
942
diff -N errors/Simplify_Chinese/ERR_ICAP_FAILURE
943
--- /dev/null	1 Jan 1970 00:00:00 -0000
944
+++ errors/Simplify_Chinese/ERR_ICAP_FAILURE	8 Dec 2003 12:31:02 -0000	1.1.2.1
945
@@ -0,0 +1,31 @@
946
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
947
+<HTML><HEAD>
948
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
949
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
950
+</HEAD><BODY>
951
+<H1>ERROR</H1>
952
+<H2>The requested URL could not be retrieved</H2>
953
+<HR noshade size="1px">
954
+<P>
955
+While attempting to retrieve the URL:
956
+<A HREF="%U">%U</A>
957
+<P>
958
+the following error was encountered:
959
+<UL>
960
+<LI>
961
+<STRONG>
962
+ICAP protocol error.
963
+</STRONG>
964
+</UL>
965
+
966
+<P>
967
+<P>
968
+Some aspect of the ICAP communication failed. Possible problems:
969
+<UL>
970
+<LI>ICAP server is not reachable.
971
+<LI>Illegal response from ICAP server.
972
+</UL>
973
+</P>
974
+
975
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
976
+
977
Index: errors/Slovak/ERR_ICAP_FAILURE
978
===================================================================
979
RCS file: errors/Slovak/ERR_ICAP_FAILURE
980
diff -N errors/Slovak/ERR_ICAP_FAILURE
981
--- /dev/null	1 Jan 1970 00:00:00 -0000
982
+++ errors/Slovak/ERR_ICAP_FAILURE	8 Dec 2003 12:31:03 -0000	1.1.2.1
983
@@ -0,0 +1,31 @@
984
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
985
+<HTML><HEAD>
986
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
987
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
988
+</HEAD><BODY>
989
+<H1>ERROR</H1>
990
+<H2>The requested URL could not be retrieved</H2>
991
+<HR noshade size="1px">
992
+<P>
993
+While attempting to retrieve the URL:
994
+<A HREF="%U">%U</A>
995
+<P>
996
+the following error was encountered:
997
+<UL>
998
+<LI>
999
+<STRONG>
1000
+ICAP protocol error.
1001
+</STRONG>
1002
+</UL>
1003
+
1004
+<P>
1005
+<P>
1006
+Some aspect of the ICAP communication failed. Possible problems:
1007
+<UL>
1008
+<LI>ICAP server is not reachable.
1009
+<LI>Illegal response from ICAP server.
1010
+</UL>
1011
+</P>
1012
+
1013
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
1014
+
1015
Index: errors/Spanish/ERR_ICAP_FAILURE
1016
===================================================================
1017
RCS file: errors/Spanish/ERR_ICAP_FAILURE
1018
diff -N errors/Spanish/ERR_ICAP_FAILURE
1019
--- /dev/null	1 Jan 1970 00:00:00 -0000
1020
+++ errors/Spanish/ERR_ICAP_FAILURE	8 Dec 2003 12:31:03 -0000	1.1.2.1
1021
@@ -0,0 +1,31 @@
1022
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
1023
+<HTML><HEAD>
1024
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
1025
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
1026
+</HEAD><BODY>
1027
+<H1>ERROR</H1>
1028
+<H2>The requested URL could not be retrieved</H2>
1029
+<HR noshade size="1px">
1030
+<P>
1031
+While attempting to retrieve the URL:
1032
+<A HREF="%U">%U</A>
1033
+<P>
1034
+the following error was encountered:
1035
+<UL>
1036
+<LI>
1037
+<STRONG>
1038
+ICAP protocol error.
1039
+</STRONG>
1040
+</UL>
1041
+
1042
+<P>
1043
+<P>
1044
+Some aspect of the ICAP communication failed. Possible problems:
1045
+<UL>
1046
+<LI>ICAP server is not reachable.
1047
+<LI>Illegal response from ICAP server.
1048
+</UL>
1049
+</P>
1050
+
1051
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
1052
+
1053
Index: errors/Swedish/ERR_ICAP_FAILURE
1054
===================================================================
1055
RCS file: errors/Swedish/ERR_ICAP_FAILURE
1056
diff -N errors/Swedish/ERR_ICAP_FAILURE
1057
--- /dev/null	1 Jan 1970 00:00:00 -0000
1058
+++ errors/Swedish/ERR_ICAP_FAILURE	8 Dec 2003 12:31:03 -0000	1.1.2.1
1059
@@ -0,0 +1,31 @@
1060
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
1061
+<HTML><HEAD>
1062
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
1063
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
1064
+</HEAD><BODY>
1065
+<H1>ERROR</H1>
1066
+<H2>The requested URL could not be retrieved</H2>
1067
+<HR noshade size="1px">
1068
+<P>
1069
+While attempting to retrieve the URL:
1070
+<A HREF="%U">%U</A>
1071
+<P>
1072
+the following error was encountered:
1073
+<UL>
1074
+<LI>
1075
+<STRONG>
1076
+ICAP protocol error.
1077
+</STRONG>
1078
+</UL>
1079
+
1080
+<P>
1081
+<P>
1082
+Some aspect of the ICAP communication failed. Possible problems:
1083
+<UL>
1084
+<LI>ICAP server is not reachable.
1085
+<LI>Illegal response from ICAP server.
1086
+</UL>
1087
+</P>
1088
+
1089
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
1090
+
1091
Index: errors/Traditional_Chinese/ERR_ICAP_FAILURE
1092
===================================================================
1093
RCS file: errors/Traditional_Chinese/ERR_ICAP_FAILURE
1094
diff -N errors/Traditional_Chinese/ERR_ICAP_FAILURE
1095
--- /dev/null	1 Jan 1970 00:00:00 -0000
1096
+++ errors/Traditional_Chinese/ERR_ICAP_FAILURE	8 Dec 2003 12:31:03 -0000	1.1.2.1
1097
@@ -0,0 +1,31 @@
1098
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
1099
+<HTML><HEAD>
1100
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
1101
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
1102
+</HEAD><BODY>
1103
+<H1>ERROR</H1>
1104
+<H2>The requested URL could not be retrieved</H2>
1105
+<HR noshade size="1px">
1106
+<P>
1107
+While attempting to retrieve the URL:
1108
+<A HREF="%U">%U</A>
1109
+<P>
1110
+the following error was encountered:
1111
+<UL>
1112
+<LI>
1113
+<STRONG>
1114
+ICAP protocol error.
1115
+</STRONG>
1116
+</UL>
1117
+
1118
+<P>
1119
+<P>
1120
+Some aspect of the ICAP communication failed. Possible problems:
1121
+<UL>
1122
+<LI>ICAP server is not reachable.
1123
+<LI>Illegal response from ICAP server.
1124
+</UL>
1125
+</P>
1126
+
1127
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
1128
+
1129
Index: errors/Turkish/ERR_ICAP_FAILURE
1130
===================================================================
1131
RCS file: errors/Turkish/ERR_ICAP_FAILURE
1132
diff -N errors/Turkish/ERR_ICAP_FAILURE
1133
--- /dev/null	1 Jan 1970 00:00:00 -0000
1134
+++ errors/Turkish/ERR_ICAP_FAILURE	8 Dec 2003 12:31:04 -0000	1.1.2.1
1135
@@ -0,0 +1,31 @@
1136
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
1137
+<HTML><HEAD>
1138
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
1139
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
1140
+</HEAD><BODY>
1141
+<H1>ERROR</H1>
1142
+<H2>The requested URL could not be retrieved</H2>
1143
+<HR noshade size="1px">
1144
+<P>
1145
+While attempting to retrieve the URL:
1146
+<A HREF="%U">%U</A>
1147
+<P>
1148
+the following error was encountered:
1149
+<UL>
1150
+<LI>
1151
+<STRONG>
1152
+ICAP protocol error.
1153
+</STRONG>
1154
+</UL>
1155
+
1156
+<P>
1157
+<P>
1158
+Some aspect of the ICAP communication failed. Possible problems:
1159
+<UL>
1160
+<LI>ICAP server is not reachable.
1161
+<LI>Illegal response from ICAP server.
1162
+</UL>
1163
+</P>
1164
+
1165
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
1166
+
1167
Index: include/util.h
1168
===================================================================
1169
RCS file: /cvsroot/squid/squid/include/util.h,v
1170
retrieving revision 1.10.6.1
1171
retrieving revision 1.10.30.3
1172
diff -p -u -b -r1.10.6.1 -r1.10.30.3
1173
--- include/util.h	12 May 2006 16:51:32 -0000	1.10.6.1
1174
+++ include/util.h	16 May 2006 17:56:57 -0000	1.10.30.3
1175
@@ -123,4 +123,12 @@ double drand48(void);
1176
  */
1177
 int statMemoryAccounted(void);
1178
 
1179
+#ifndef HAVE_STRNSTR
1180
+extern char *strnstr(const char *haystack, const char *needle, size_t haystacklen);
1181
+#endif
1182
+
1183
+#ifndef HAVE_STRCASESTR
1184
+extern char *strcasestr(const char *haystack, const char *needle);
1185
+#endif
1186
+
1187
 #endif /* SQUID_UTIL_H */
1188
Index: lib/strcasestr.c
1189
===================================================================
1190
RCS file: lib/strcasestr.c
1191
diff -N lib/strcasestr.c
1192
--- /dev/null	1 Jan 1970 00:00:00 -0000
1193
+++ lib/strcasestr.c	6 Apr 2004 13:04:38 -0000	1.1.2.1
1194
@@ -0,0 +1,126 @@
1195
+/* Return the offset of one string within another.
1196
+   Copyright (C) 1994,1996,1997,1998,1999,2000 Free Software Foundation, Inc.
1197
+   This file is part of the GNU C Library.
1198
+
1199
+   The GNU C Library is free software; you can redistribute it and/or
1200
+   modify it under the terms of the GNU Lesser General Public
1201
+   License as published by the Free Software Foundation; either
1202
+   version 2.1 of the License, or (at your option) any later version.
1203
+
1204
+   The GNU C Library is distributed in the hope that it will be useful,
1205
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
1206
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1207
+   Lesser General Public License for more details.
1208
+
1209
+   You should have received a copy of the GNU Lesser General Public
1210
+   License along with the GNU C Library; if not, write to the Free
1211
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
1212
+   02111-1307 USA.  */
1213
+
1214
+/*
1215
+ * My personal strstr() implementation that beats most other algorithms.
1216
+ * Until someone tells me otherwise, I assume that this is the
1217
+ * fastest implementation of strstr() in C.
1218
+ * I deliberately chose not to comment it.  You should have at least
1219
+ * as much fun trying to understand it, as I had to write it :-).
1220
+ *
1221
+ * Stephen R. van den Berg, berg@pool.informatik.rwth-aachen.de	*/
1222
+
1223
+/* 
1224
+ * modified to work outside of glibc (rhorstmann, 06/04/2004)
1225
+ */
1226
+
1227
+#include "config.h"
1228
+#ifndef  HAVE_STRCASESTR
1229
+#include <ctype.h>
1230
+
1231
+typedef unsigned chartype;
1232
+
1233
+char *
1234
+strcasestr (phaystack, pneedle)
1235
+     const char *phaystack;
1236
+     const char *pneedle;
1237
+{
1238
+  register const unsigned char *haystack, *needle;
1239
+  register chartype b, c;
1240
+
1241
+  haystack = (const unsigned char *) phaystack;
1242
+  needle = (const unsigned char *) pneedle;
1243
+
1244
+  b = tolower (*needle);
1245
+  if (b != '\0')
1246
+    {
1247
+      haystack--;				/* possible ANSI violation */
1248
+      do
1249
+	{
1250
+	  c = *++haystack;
1251
+	  if (c == '\0')
1252
+	    goto ret0;
1253
+	}
1254
+      while (tolower (c) != (int) b);
1255
+
1256
+      c = tolower (*++needle);
1257
+      if (c == '\0')
1258
+	goto foundneedle;
1259
+      ++needle;
1260
+      goto jin;
1261
+
1262
+      for (;;)
1263
+        {
1264
+          register chartype a;
1265
+	  register const unsigned char *rhaystack, *rneedle;
1266
+
1267
+	  do
1268
+	    {
1269
+	      a = *++haystack;
1270
+	      if (a == '\0')
1271
+		goto ret0;
1272
+	      if (tolower (a) == (int) b)
1273
+		break;
1274
+	      a = *++haystack;
1275
+	      if (a == '\0')
1276
+		goto ret0;
1277
+shloop:
1278
+	      ;
1279
+	    }
1280
+          while (tolower (a) != (int) b);
1281
+
1282
+jin:	  a = *++haystack;
1283
+	  if (a == '\0')
1284
+	    goto ret0;
1285
+
1286
+	  if (tolower (a) != (int) c)
1287
+	    goto shloop;
1288
+
1289
+	  rhaystack = haystack-- + 1;
1290
+	  rneedle = needle;
1291
+	  a = tolower (*rneedle);
1292
+
1293
+	  if (tolower (*rhaystack) == (int) a)
1294
+	    do
1295
+	      {
1296
+		if (a == '\0')
1297
+		  goto foundneedle;
1298
+		++rhaystack;
1299
+		a = tolower (*++needle);
1300
+		if (tolower (*rhaystack) != (int) a)
1301
+		  break;
1302
+		if (a == '\0')
1303
+		  goto foundneedle;
1304
+		++rhaystack;
1305
+		a = tolower (*++needle);
1306
+	      }
1307
+	    while (tolower (*rhaystack) == (int) a);
1308
+
1309
+	  needle = rneedle;		/* took the register-poor approach */
1310
+
1311
+	  if (a == '\0')
1312
+	    break;
1313
+        }
1314
+    }
1315
+foundneedle:
1316
+  return (char*) haystack;
1317
+ret0:
1318
+  return 0;
1319
+}
1320
+#endif
1321
Index: lib/strnstr.c
1322
===================================================================
1323
RCS file: lib/strnstr.c
1324
diff -N lib/strnstr.c
1325
--- /dev/null	1 Jan 1970 00:00:00 -0000
1326
+++ lib/strnstr.c	16 May 2005 20:52:40 -0000	1.1.2.2
1327
@@ -0,0 +1,52 @@
1328
+/*
1329
+ *  Copyright (C) 2003 Nikos Mavroyanopoulos
1330
+ *
1331
+ *  This file is part of GNUTLS.
1332
+ *
1333
+ *  The GNUTLS library is free software; you can redistribute it and/or
1334
+ *  modify it under the terms of the GNU Lesser General Public   
1335
+ *  License as published by the Free Software Foundation; either 
1336
+ *  version 2.1 of the License, or (at your option) any later version.
1337
+ *
1338
+ *  This library is distributed in the hope that it will be useful,
1339
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
1340
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1341
+ *  Lesser General Public License for more details.
1342
+ *
1343
+ *  You should have received a copy of the GNU Lesser General Public
1344
+ *  License along with this library; if not, write to the Free Software
1345
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
1346
+ *
1347
+ */
1348
+
1349
+ /*
1350
+  * DW 2003/10/17:
1351
+  * Changed 'ssize_t' types to 'size_t'
1352
+  */
1353
+
1354
+#include "config.h"
1355
+#ifndef HAVE_STRNSTR
1356
+#include <string.h>
1357
+#include <util.h>
1358
+
1359
+char *strnstr(const char *haystack, const char *needle, size_t haystacklen)
1360
+{
1361
+        char *p;
1362
+        size_t plen;
1363
+        size_t len = strlen(needle);
1364
+
1365
+        if (*needle == '\0')    /* everything matches empty string */
1366
+                return (char*) haystack;
1367
+
1368
+        plen = haystacklen;
1369
+        for (p = (char*) haystack; p != NULL; p = memchr(p + 1, *needle, plen-1)) {
1370
+                plen = haystacklen - (p - haystack);
1371
+
1372
+                if (plen < len) return NULL;
1373
+
1374
+                if (strncmp(p, needle, len) == 0)
1375
+                        return (p);
1376
+        }
1377
+        return NULL;
1378
+}
1379
+#endif
1380
Index: src/MemBuf.c
1381
===================================================================
1382
RCS file: /cvsroot/squid/squid/src/MemBuf.c,v
1383
retrieving revision 1.5.30.3
1384
retrieving revision 1.5.44.8
1385
diff -p -u -b -r1.5.30.3 -r1.5.44.8
1386
--- src/MemBuf.c	26 Mar 2005 03:15:54 -0000	1.5.30.3
1387
+++ src/MemBuf.c	28 Mar 2005 18:02:04 -0000	1.5.44.8
1388
@@ -386,3 +386,15 @@ memBufReport(MemBuf * mb)
1389
     assert(mb);
1390
     memBufPrintf(mb, "memBufReport is not yet implemented @?@\n");
1391
 }
1392
+
1393
+int
1394
+memBufRead(int fd, MemBuf * mb)
1395
+{
1396
+    int len;
1397
+    if (mb->capacity == mb->size)
1398
+	memBufGrow(mb, SQUID_TCP_SO_RCVBUF);
1399
+    len = FD_READ_METHOD(fd, mb->buf + mb->size, mb->capacity - mb->size);
1400
+    if (len)
1401
+	mb->size += len;
1402
+    return len;
1403
+}
1404
Index: src/cache_cf.c
1405
===================================================================
1406
RCS file: /cvsroot/squid/squid/src/cache_cf.c,v
1407
retrieving revision 1.38.6.29
1408
retrieving revision 1.38.6.11.2.22
1409
diff -p -u -b -r1.38.6.29 -r1.38.6.11.2.22
1410
--- src/cache_cf.c	27 Oct 2005 02:13:24 -0000	1.38.6.29
1411
+++ src/cache_cf.c	23 Nov 2005 20:38:56 -0000	1.38.6.11.2.22
1412
@@ -2198,6 +2198,587 @@ check_null_body_size_t(dlink_list bodyli
1413
     return bodylist.head == NULL;
1414
 }
1415
 
1416
+#ifdef HS_FEAT_ICAP
1417
+
1418
+/***************************************************
1419
+ * prototypes
1420
+ */
1421
+static int icap_service_process(icap_service * s);
1422
+static void icap_service_init(icap_service * s);
1423
+static void icap_service_destroy(icap_service * s);
1424
+icap_service *icap_service_lookup(char *name);
1425
+static int icap_class_process(icap_class * c);
1426
+static void icap_class_destroy(icap_class * c);
1427
+static void icap_access_destroy(icap_access * a);
1428
+static void dump_wordlist(StoreEntry * entry, const char *name, wordlist * list);
1429
+static void icap_class_add(icap_class * c);
1430
+
1431
+/***************************************************
1432
+ * icap_service
1433
+ */
1434
+
1435
+/* 
1436
+ * example:
1437
+ * icap_service reqmode_precache 0 icap://192.168.0.1:1344/respmod
1438
+ */
1439
+
1440
+static void
1441
+parse_icap_service_type(IcapConfig * cfg)
1442
+{
1443
+    char *token;
1444
+    icap_service *A = NULL;
1445
+    icap_service *B = NULL;
1446
+    icap_service **T = NULL;
1447
+
1448
+    A = cbdataAlloc(icap_service);
1449
+    icap_service_init(A);
1450
+    parse_string(&A->name);
1451
+    parse_string(&A->type_name);
1452
+    parse_ushort(&A->bypass);
1453
+    parse_string(&A->uri);
1454
+    while ((token = strtok(NULL, w_space))) {
1455
+	if (strcasecmp(token, "no-keep-alive") == 0) {
1456
+	    A->keep_alive = 0;
1457
+	} else {
1458
+	    debug(3, 0) ("parse_peer: token='%s'\n", token);
1459
+	    self_destruct();
1460
+	}
1461
+    }
1462
+    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);
1463
+    if (icap_service_process(A)) {
1464
+	/* put into linked list */
1465
+	for (B = cfg->service_head, T = &cfg->service_head; B; T = &B->next, B = B->next);
1466
+	*T = A;
1467
+    } else {
1468
+	/* clean up structure */
1469
+	debug(3, 0) ("parse_icap_service_type (line %d): skipping %s\n", config_lineno, A->name);
1470
+	icap_service_destroy(A);
1471
+	cbdataFree(A);
1472
+    }
1473
+
1474
+}
1475
+
1476
+static void
1477
+dump_icap_service_type(StoreEntry * e, const char *name, IcapConfig cfg)
1478
+{
1479
+    icap_service *current_node = NULL;
1480
+
1481
+    if (!cfg.service_head) {
1482
+	storeAppendPrintf(e, "%s 0\n", name);
1483
+	return;
1484
+    }
1485
+    current_node = cfg.service_head;
1486
+
1487
+    while (current_node) {
1488
+	storeAppendPrintf(e, "%s %s %s %d %s", name, current_node->name, current_node->type_name, current_node->bypass, current_node->uri);
1489
+	if (current_node->keep_alive == 0) {
1490
+	    storeAppendPrintf(e, " no-keep-alive");
1491
+	}
1492
+	storeAppendPrintf(e, "\n");
1493
+	current_node = current_node->next;
1494
+    }
1495
+
1496
+}
1497
+
1498
+static void
1499
+free_icap_service_type(IcapConfig * cfg)
1500
+{
1501
+    while (cfg->service_head) {
1502
+	icap_service *current_node = cfg->service_head;
1503
+	cfg->service_head = current_node->next;
1504
+	icap_service_destroy(current_node);
1505
+	cbdataFree(current_node);
1506
+    }
1507
+}
1508
+
1509
+/* 
1510
+ * parse the raw string and cache some parts that are needed later 
1511
+ * returns 1 if everything was ok
1512
+ */
1513
+static int
1514
+icap_service_process(icap_service * s)
1515
+{
1516
+    char *start, *end, *tempEnd;
1517
+    char *tailp;
1518
+    unsigned int len;
1519
+    int port_in_uri, resource_in_uri = 0;
1520
+    s->type = icapServiceToType(s->type_name);
1521
+    if (s->type >= ICAP_SERVICE_MAX) {
1522
+	debug(3, 0) ("icap_service_process (line %d): wrong service type %s\n", config_lineno, s->type_name);
1523
+	return 0;
1524
+    }
1525
+    if (s->type == ICAP_SERVICE_REQMOD_PRECACHE)
1526
+	s->method = ICAP_METHOD_REQMOD;
1527
+    else if (s->type == ICAP_SERVICE_REQMOD_PRECACHE)
1528
+	s->method = ICAP_METHOD_REQMOD;
1529
+    else if (s->type == ICAP_SERVICE_REQMOD_POSTCACHE)
1530
+	s->method = ICAP_METHOD_REQMOD;
1531
+    else if (s->type == ICAP_SERVICE_RESPMOD_PRECACHE)
1532
+	s->method = ICAP_METHOD_RESPMOD;
1533
+    else if (s->type == ICAP_SERVICE_RESPMOD_POSTCACHE)
1534
+	s->method = ICAP_METHOD_RESPMOD;
1535
+    debug(3, 5) ("icap_service_process (line %d): type=%s\n", config_lineno, icapServiceToStr(s->type));
1536
+    if (strncmp(s->uri, "icap://", 7) != 0) {
1537
+	debug(3, 0) ("icap_service_process (line %d): wrong uri: %s\n", config_lineno, s->uri);
1538
+	return 0;
1539
+    }
1540
+    start = s->uri + 7;
1541
+    if ((end = strchr(start, ':')) != NULL) {
1542
+	/* ok */
1543
+	port_in_uri = 1;
1544
+	debug(3, 5) ("icap_service_process (line %d): port given\n", config_lineno);
1545
+    } else {
1546
+	/* ok */
1547
+	port_in_uri = 0;
1548
+	debug(3, 5) ("icap_service_process (line %d): no port given\n", config_lineno);
1549
+    }
1550
+
1551
+    if ((tempEnd = strchr(start, '/')) != NULL) {
1552
+	/* ok */
1553
+	resource_in_uri = 1;
1554
+	debug(3, 5) ("icap_service_process (line %d): resource given\n", config_lineno);
1555
+	if (end == '\0') {
1556
+	    end = tempEnd;
1557
+	}
1558
+    } else {
1559
+	/* ok */
1560
+	resource_in_uri = 0;
1561
+	debug(3, 5) ("icap_service_process (line %d): no resource given\n", config_lineno);
1562
+    }
1563
+
1564
+    tempEnd = strchr(start, '\0');
1565
+    if (end == '\0') {
1566
+	end = tempEnd;
1567
+    }
1568
+    len = end - start;
1569
+    s->hostname = xstrndup(start, len + 1);
1570
+    s->hostname[len] = 0;
1571
+    debug(3, 5) ("icap_service_process (line %d): hostname=%s\n", config_lineno, s->hostname);
1572
+    start = end;
1573
+
1574
+    if (port_in_uri) {
1575
+	start++;		/* skip ':' */
1576
+	if (resource_in_uri)
1577
+	    end = strchr(start, '/');
1578
+	else
1579
+	    end = strchr(start, '\0');
1580
+	s->port = strtoul(start, &tailp, 0) % 65536;
1581
+	if (tailp != end) {
1582
+	    debug(3, 0) ("icap_service_process (line %d): wrong service uri (port could not be parsed): %s\n", config_lineno, s->uri);
1583
+	    return 0;
1584
+	}
1585
+	debug(3, 5) ("icap_service_process (line %d): port=%d\n", config_lineno, s->port);
1586
+	start = end;
1587
+    } else {
1588
+	/* no explicit ICAP port; first ask by getservbyname or default to
1589
+	 * hardwired port 1344 per ICAP specification section 4.2 */
1590
+	struct servent *serv = getservbyname("icap", "tcp");
1591
+	if (serv) {
1592
+	    s->port = htons(serv->s_port);
1593
+	    debug(3, 5) ("icap_service_process (line %d): default port=%d getservbyname(icap,tcp)\n", config_lineno, s->port);
1594
+	} else {
1595
+	    s->port = 1344;
1596
+	    debug(3, 5) ("icap_service_process (line %d): default hardwired port=%d\n", config_lineno, s->port);
1597
+	}
1598
+    }
1599
+
1600
+    if (resource_in_uri) {
1601
+	start++;		/* skip '/' */
1602
+	/* the rest is resource name */
1603
+	end = strchr(start, '\0');
1604
+	len = end - start;
1605
+	if (len > 1024) {
1606
+	    debug(3, 0) ("icap_service_process (line %d): long resource name (>1024), probably wrong\n", config_lineno);
1607
+	}
1608
+	s->resource = xstrndup(start, len + 1);
1609
+	s->resource[len] = 0;
1610
+	debug(3, 5) ("icap_service_process (line %d): service=%s\n", config_lineno, s->resource);
1611
+    }
1612
+    /* check bypass */
1613
+    if ((s->bypass != 0) && (s->bypass != 1)) {
1614
+	debug(3, 0) ("icap_service_process (line %d): invalid bypass value\n", config_lineno);
1615
+	return 0;
1616
+    }
1617
+    return 1;
1618
+}
1619
+
1620
+/*
1621
+ * constructor
1622
+ */
1623
+static void
1624
+icap_service_init(icap_service * s)
1625
+{
1626
+    s->type = ICAP_SERVICE_MAX;	/* means undefined */
1627
+    s->preview = Config.icapcfg.preview_size;
1628
+    s->opt = 0;
1629
+    s->keep_alive = 1;
1630
+    s->istag = StringNull;
1631
+    s->transfer_preview = StringNull;
1632
+    s->transfer_ignore = StringNull;
1633
+    s->transfer_complete = StringNull;
1634
+}
1635
+
1636
+/*
1637
+ * destructor
1638
+ * frees only strings, but don't touch the linked list
1639
+ */
1640
+static void
1641
+icap_service_destroy(icap_service * s)
1642
+{
1643
+    xfree(s->name);
1644
+    xfree(s->uri);
1645
+    xfree(s->type_name);
1646
+    xfree(s->hostname);
1647
+    xfree(s->resource);
1648
+    assert(s->opt == 0);	/* there should be no opt request running now */
1649
+    stringClean(&s->istag);
1650
+    stringClean(&s->transfer_preview);
1651
+    stringClean(&s->transfer_ignore);
1652
+    stringClean(&s->transfer_complete);
1653
+}
1654
+
1655
+icap_service *
1656
+icap_service_lookup(char *name)
1657
+{
1658
+    icap_service *iter;
1659
+    for (iter = Config.icapcfg.service_head; iter; iter = iter->next) {
1660
+	if (!strcmp(name, iter->name)) {
1661
+	    return iter;
1662
+	}
1663
+    }
1664
+    return NULL;
1665
+}
1666
+
1667
+/***************************************************
1668
+ * icap_service_list
1669
+ */
1670
+
1671
+static void
1672
+icap_service_list_add(icap_service_list ** isl, char *service_name)
1673
+{
1674
+    icap_service_list **iter;
1675
+    icap_service_list *new;
1676
+    icap_service *gbl_service;
1677
+    int i;
1678
+    int max_services;
1679
+
1680
+    new = memAllocate(MEM_ICAP_SERVICE_LIST);
1681
+    /* Found all services with that name, and add to the array */
1682
+    max_services = sizeof(new->services) / sizeof(icap_service *);
1683
+    gbl_service = Config.icapcfg.service_head;
1684
+    i = 0;
1685
+    while (gbl_service && i < max_services) {
1686
+	if (!strcmp(service_name, gbl_service->name))
1687
+	    new->services[i++] = gbl_service;
1688
+	gbl_service = gbl_service->next;
1689
+    }
1690
+    new->nservices = i;
1691
+
1692
+    if (*isl) {
1693
+	iter = isl;
1694
+	while ((*iter)->next)
1695
+	    iter = &((*iter)->next);
1696
+	(*iter)->next = new;
1697
+    } else {
1698
+	*isl = new;
1699
+    }
1700
+}
1701
+
1702
+/*
1703
+ * free the linked list without touching references icap_service
1704
+ */
1705
+static void
1706
+icap_service_list_destroy(icap_service_list * isl)
1707
+{
1708
+    icap_service_list *current;
1709
+    icap_service_list *next;
1710
+
1711
+    current = isl;
1712
+    while (current) {
1713
+	next = current->next;
1714
+	memFree(current, MEM_ICAP_SERVICE_LIST);
1715
+	current = next;
1716
+    }
1717
+}
1718
+
1719
+/***************************************************
1720
+ * icap_class
1721
+ */
1722
+static void
1723
+parse_icap_class_type(IcapConfig * cfg)
1724
+{
1725
+    icap_class *s = NULL;
1726
+
1727
+    s = memAllocate(MEM_ICAP_CLASS);
1728
+    parse_string(&s->name);
1729
+    parse_wordlist(&s->services);
1730
+
1731
+    if (icap_class_process(s)) {
1732
+	/* if ok, put into linked list */
1733
+	icap_class_add(s);
1734
+    } else {
1735
+	/* clean up structure */
1736
+	debug(3, 0) ("parse_icap_class_type (line %d): skipping %s\n", config_lineno, s->name);
1737
+	icap_class_destroy(s);
1738
+	memFree(s, MEM_ICAP_CLASS);
1739
+    }
1740
+}
1741
+
1742
+static void
1743
+dump_icap_class_type(StoreEntry * e, const char *name, IcapConfig cfg)
1744
+{
1745
+    icap_class *current_node = NULL;
1746
+    LOCAL_ARRAY(char, nom, 64);
1747
+
1748
+    if (!cfg.class_head) {
1749
+	storeAppendPrintf(e, "%s 0\n", name);
1750
+	return;
1751
+    }
1752
+    current_node = cfg.class_head;
1753
+
1754
+    while (current_node) {
1755
+	snprintf(nom, 64, "%s %s", name, current_node->name);
1756
+	dump_wordlist(e, nom, current_node->services);
1757
+	current_node = current_node->next;
1758
+    }
1759
+}
1760
+
1761
+static void
1762
+free_icap_class_type(IcapConfig * cfg)
1763
+{
1764
+    while (cfg->class_head) {
1765
+	icap_class *current_node = cfg->class_head;
1766
+	cfg->class_head = current_node->next;
1767
+	icap_class_destroy(current_node);
1768
+	memFree(current_node, MEM_ICAP_CLASS);
1769
+    }
1770
+}
1771
+
1772
+/*
1773
+ * process services list, return 1, if at least one service was found
1774
+ */
1775
+static int
1776
+icap_class_process(icap_class * c)
1777
+{
1778
+    icap_service_list *isl = NULL;
1779
+    wordlist *iter;
1780
+    icap_service *service;
1781
+    /* take services list and build icap_service_list from it */
1782
+    for (iter = c->services; iter; iter = iter->next) {
1783
+	service = icap_service_lookup(iter->key);
1784
+	if (service) {
1785
+	    icap_service_list_add(&isl, iter->key);
1786
+	} else {
1787
+	    debug(3, 0) ("icap_class_process (line %d): skipping service %s in class %s\n", config_lineno, iter->key, c->name);
1788
+	}
1789
+    }
1790
+
1791
+    if (isl) {
1792
+	c->isl = isl;
1793
+	return 1;
1794
+    }
1795
+    return 0;
1796
+}
1797
+
1798
+/*
1799
+ * search for an icap_class in the global IcapConfig
1800
+ * classes with hidden-flag are skipped
1801
+ */
1802
+static icap_class *
1803
+icap_class_lookup(char *name)
1804
+{
1805
+    icap_class *iter;
1806
+    for (iter = Config.icapcfg.class_head; iter; iter = iter->next) {
1807
+	if ((!strcmp(name, iter->name)) && (!iter->hidden)) {
1808
+	    return iter;
1809
+	}
1810
+    }
1811
+    return NULL;
1812
+}
1813
+
1814
+/*
1815
+ * adds an icap_class to the global IcapConfig
1816
+ */
1817
+static void
1818
+icap_class_add(icap_class * c)
1819
+{
1820
+    icap_class *cp = NULL;
1821
+    icap_class **t = NULL;
1822
+    IcapConfig *cfg = &Config.icapcfg;
1823
+    if (c) {
1824
+	for (cp = cfg->class_head, t = &cfg->class_head; cp; t = &cp->next, cp = cp->next);
1825
+	*t = c;
1826
+    }
1827
+}
1828
+
1829
+/*
1830
+ * free allocated memory inside icap_class
1831
+ */
1832
+static void
1833
+icap_class_destroy(icap_class * c)
1834
+{
1835
+    xfree(c->name);
1836
+    wordlistDestroy(&c->services);
1837
+    icap_service_list_destroy(c->isl);
1838
+}
1839
+
1840
+/***************************************************
1841
+ * icap_access
1842
+ */
1843
+
1844
+/* format: icap_access <servicename> {allow|deny} acl, ... */
1845
+static void
1846
+parse_icap_access_type(IcapConfig * cfg)
1847
+{
1848
+    icap_access *A = NULL;
1849
+    icap_access *B = NULL;
1850
+    icap_access **T = NULL;
1851
+    icap_service *s = NULL;
1852
+    icap_class *c = NULL;
1853
+    ushort no_class = 0;
1854
+
1855
+    A = memAllocate(MEM_ICAP_ACCESS);
1856
+    parse_string(&A->service_name);
1857
+
1858
+    /* 
1859
+     * try to find a class with the given name first. if not found, search 
1860
+     * the services. if a service is found, create a new hidden class with 
1861
+     * only this service. this is for backward compatibility.
1862
+     *
1863
+     * the special classname All is allowed only in deny rules, because
1864
+     * the class is not used there.
1865
+     */
1866
+    if (!strcmp(A->service_name, "None")) {
1867
+	no_class = 1;
1868
+    } else {
1869
+	A->class = icap_class_lookup(A->service_name);
1870
+	if (!A->class) {
1871
+	    s = icap_service_lookup(A->service_name);
1872
+	    if (s) {
1873
+		c = memAllocate(MEM_ICAP_CLASS);
1874
+		c->name = xstrdup("(hidden)");
1875
+		c->hidden = 1;
1876
+		wordlistAdd(&c->services, A->service_name);
1877
+		c->isl = memAllocate(MEM_ICAP_SERVICE_LIST);
1878
+		/* FIXME:luc: check what access do */
1879
+		c->isl->services[0] = s;
1880
+		c->isl->nservices = 1;
1881
+		icap_class_add(c);
1882
+		A->class = c;
1883
+	    } else {
1884
+		debug(3, 0) ("parse_icap_access_type (line %d): servicename %s not found. skipping.\n", config_lineno, A->service_name);
1885
+		memFree(A, MEM_ICAP_ACCESS);
1886
+		return;
1887
+	    }
1888
+	}
1889
+    }
1890
+
1891
+    aclParseAccessLine(&(A->access));
1892
+    debug(3, 5) ("parse_icap_access_type (line %d): %s\n", config_lineno, A->service_name);
1893
+
1894
+    /* check that All class is only used in deny rule */
1895
+    if (no_class && A->access->allow) {
1896
+	memFree(A, MEM_ICAP_ACCESS);
1897
+	debug(3, 0) ("parse_icap_access (line %d): special class 'None' only allowed in deny rule. skipping.\n", config_lineno);
1898
+	return;
1899
+    }
1900
+    if (A->access) {
1901
+	for (B = cfg->access_head, T = &cfg->access_head; B; T = &B->next, B = B->next);
1902
+	*T = A;
1903
+    } else {
1904
+	debug(3, 0) ("parse_icap_access_type (line %d): invalid line skipped\n", config_lineno);
1905
+	memFree(A, MEM_ICAP_ACCESS);
1906
+    }
1907
+}
1908
+
1909
+static void
1910
+dump_icap_access_type(StoreEntry * e, const char *name, IcapConfig cfg)
1911
+{
1912
+    icap_access *current_node = NULL;
1913
+    LOCAL_ARRAY(char, nom, 64);
1914
+
1915
+    if (!cfg.access_head) {
1916
+	storeAppendPrintf(e, "%s 0\n", name);
1917
+	return;
1918
+    }
1919
+    current_node = cfg.access_head;
1920
+
1921
+    while (current_node) {
1922
+	snprintf(nom, 64, "%s %s", name, current_node->service_name);
1923
+	dump_acl_access(e, nom, current_node->access);
1924
+	current_node = current_node->next;
1925
+    }
1926
+}
1927
+
1928
+static void
1929
+free_icap_access_type(IcapConfig * cfg)
1930
+{
1931
+    while (cfg->access_head) {
1932
+	icap_access *current_node = cfg->access_head;
1933
+	cfg->access_head = current_node->next;
1934
+	icap_access_destroy(current_node);
1935
+	memFree(current_node, MEM_ICAP_ACCESS);
1936
+    }
1937
+}
1938
+
1939
+/*
1940
+ * destructor
1941
+ * frees everything but the linked list
1942
+ */
1943
+static void
1944
+icap_access_destroy(icap_access * a)
1945
+{
1946
+    xfree(a->service_name);
1947
+    aclDestroyAccessList(&a->access);
1948
+}
1949
+
1950
+/***************************************************
1951
+ * for debugging purposes only
1952
+ */
1953
+void
1954
+dump_icap_config(IcapConfig * cfg)
1955
+{
1956
+    icap_service *s_iter;
1957
+    icap_class *c_iter;
1958
+    icap_access *a_iter;
1959
+    icap_service_list *isl_iter;
1960
+    acl_list *l;
1961
+    debug(3, 0) ("IcapConfig: onoff        = %d\n", cfg->onoff);
1962
+    debug(3, 0) ("IcapConfig: service_head = %d\n", (int) cfg->service_head);
1963
+    debug(3, 0) ("IcapConfig: class_head   = %d\n", (int) cfg->class_head);
1964
+    debug(3, 0) ("IcapConfig: access_head  = %d\n", (int) cfg->access_head);
1965
+
1966
+    debug(3, 0) ("IcapConfig: services =\n");
1967
+    for (s_iter = cfg->service_head; s_iter; s_iter = s_iter->next) {
1968
+	printf("  %s: \n", s_iter->name);
1969
+	printf("    bypass   = %d\n", s_iter->bypass);
1970
+	printf("    hostname = %s\n", s_iter->hostname);
1971
+	printf("    port     = %d\n", s_iter->port);
1972
+	printf("    resource = %s\n", s_iter->resource);
1973
+    }
1974
+    debug(3, 0) ("IcapConfig: classes =\n");
1975
+    for (c_iter = cfg->class_head; c_iter; c_iter = c_iter->next) {
1976
+	printf("  %s: \n", c_iter->name);
1977
+	printf("    services = \n");
1978
+	for (isl_iter = c_iter->isl; isl_iter; isl_iter = isl_iter->next) {
1979
+	    int i;
1980
+	    for (i = 0; i < isl_iter->nservices; i++)
1981
+		printf("      %s\n", isl_iter->services[i]->name);
1982
+	}
1983
+    }
1984
+    debug(3, 0) ("IcapConfig: access =\n");
1985
+    for (a_iter = cfg->access_head; a_iter; a_iter = a_iter->next) {
1986
+	printf("  service_name  = %s\n", a_iter->service_name);
1987
+	printf("    access        = %s", a_iter->access->allow ? "allow" : "deny");
1988
+	for (l = a_iter->access->acl_list; l != NULL; l = l->next) {
1989
+	    printf(" %s%s",
1990
+		l->op ? null_string : "!",
1991
+		l->acl->name);
1992
+	}
1993
+	printf("\n");
1994
+    }
1995
+}
1996
+#endif /* HS_FEAT_ICAP */
1997
 
1998
 static void
1999
 parse_kb_size_t(squid_off_t * var)
2000
Index: src/cbdata.c
2001
===================================================================
2002
RCS file: /cvsroot/squid/squid/src/cbdata.c,v
2003
retrieving revision 1.14.6.1
2004
retrieving revision 1.14.32.2
2005
diff -p -u -b -r1.14.6.1 -r1.14.32.2
2006
--- src/cbdata.c	17 Jul 2003 02:13:28 -0000	1.14.6.1
2007
+++ src/cbdata.c	14 Sep 2003 01:36:26 -0000	1.14.32.2
2008
@@ -144,6 +144,10 @@ cbdataInit(void)
2009
     CREATE_CBDATA(statefulhelper);
2010
     CREATE_CBDATA(helper_stateful_server);
2011
     CREATE_CBDATA(HttpStateData);
2012
+#ifdef HS_FEAT_ICAP
2013
+    CREATE_CBDATA(IcapStateData);
2014
+    CREATE_CBDATA(icap_service);
2015
+#endif
2016
     CREATE_CBDATA_FREE(peer, peerDestroy);
2017
     CREATE_CBDATA(ps_state);
2018
     CREATE_CBDATA(RemovalPolicy);
2019
Index: src/cf.data.pre
2020
===================================================================
2021
RCS file: /cvsroot/squid/squid/src/cf.data.pre,v
2022
retrieving revision 1.49.2.86
2023
retrieving revision 1.49.2.33.2.34
2024
diff -p -u -b -r1.49.2.86 -r1.49.2.33.2.34
2025
--- src/cf.data.pre	26 Feb 2006 03:13:57 -0000	1.49.2.86
2026
+++ src/cf.data.pre	16 May 2006 17:56:57 -0000	1.49.2.33.2.34
2027
@@ -2397,7 +2397,6 @@ DOC_START
2028
 	ensure correct results it is best to set server_persisten_connections
2029
 	to off when using this directive in such configurations.
2030
 DOC_END
2031
-
2032
 NAME: reply_header_max_size
2033
 COMMENT: (KB)
2034
 TYPE: b_size_t
2035
@@ -2716,6 +2715,187 @@ DOC_START
2036
 DOC_END
2037
 
2038
 COMMENT_START
2039
+ ICAP OPTIONS
2040
+ -----------------------------------------------------------------------------
2041
+COMMENT_END
2042
+
2043
+NAME: icap_enable
2044
+TYPE: onoff
2045
+IFDEF: HS_FEAT_ICAP
2046
+COMMENT: on|off
2047
+LOC: Config.icapcfg.onoff
2048
+DEFAULT: off
2049
+DOC_START
2050
+	If you want to enable the ICAP client module, set this to on.
2051
+DOC_END
2052
+
2053
+NAME: icap_preview_enable
2054
+TYPE: onoff
2055
+IFDEF: HS_FEAT_ICAP
2056
+COMMENT: on|off
2057
+LOC: Config.icapcfg.preview_enable
2058
+DEFAULT: off
2059
+DOC_START
2060
+	Set this to 'on' if you want to enable the ICAP preview
2061
+	feature in Squid.
2062
+DOC_END
2063
+
2064
+NAME: icap_preview_size
2065
+TYPE: int
2066
+IFDEF: HS_FEAT_ICAP
2067
+LOC: Config.icapcfg.preview_size
2068
+DEFAULT: -1
2069
+DOC_START
2070
+	The default size of preview data to be sent to the ICAP server.
2071
+	-1 means no preview. This value might be overwritten on a per server
2072
+	basis by OPTIONS requests.
2073
+DOC_END
2074
+
2075
+NAME: icap_check_interval
2076
+TYPE: int
2077
+IFDEF: HS_FEAT_ICAP
2078
+LOC: Config.icapcfg.check_interval
2079
+DEFAULT: 300
2080
+DOC_START
2081
+        If an ICAP server does not respond, it gets marked as unreachable. Squid
2082
+	will try again to reach it after this time.
2083
+DOC_END
2084
+
2085
+NAME: icap_send_client_ip
2086
+TYPE: onoff
2087
+IFDEF: HS_FEAT_ICAP
2088
+COMMENT: on|off
2089
+LOC: Config.icapcfg.send_client_ip
2090
+DEFAULT: off
2091
+DOC_START
2092
+	Allows Squid to add the "X-Client-IP" header if requested by
2093
+	an ICAP service in it's response to OPTIONS.
2094
+DOC_END
2095
+
2096
+NAME: icap_send_server_ip
2097
+TYPE: onoff
2098
+IFDEF: HS_FEAT_ICAP
2099
+COMMENT: on|off
2100
+LOC: Config.icapcfg.send_server_ip
2101
+DEFAULT: off
2102
+DOC_START
2103
+	Allows Squid to add the "X-Server-IP" header if requested by
2104
+	an ICAP service in it's response to OPTIONS.
2105
+DOC_END
2106
+
2107
+NAME: icap_send_auth_user
2108
+TYPE: onoff
2109
+IFDEF: HS_FEAT_ICAP
2110
+COMMENT: on|off
2111
+LOC: Config.icapcfg.send_auth_user
2112
+DEFAULT: off
2113
+DOC_START
2114
+	Allows Squid to add the "X-Authenticated-User" header if requested
2115
+	by an ICAP service in it's response to OPTIONS.
2116
+DOC_END
2117
+
2118
+NAME: icap_auth_scheme
2119
+TYPE: string
2120
+IFDEF: HS_FEAT_ICAP
2121
+LOC: Config.icapcfg.auth_scheme
2122
+DEFAULT: Local://%u
2123
+DOC_START
2124
+	Authentification scheme to pass to ICAP requests if
2125
+	icap_send_auth_user is enabled. The first occurence of "%u"
2126
+	is replaced by the authentified user name. If no "%u" is found,
2127
+	the username is added at the end of the scheme.
2128
+	
2129
+	See http://www.ietf.org/internet-drafts/draft-stecher-icap-subid-00.txt,
2130
+	section 3.4 for details on this.
2131
+
2132
+	Examples:
2133
+
2134
+	icap_auth_scheme Local://%u
2135
+	icap_auth_scheme LDAP://ldap-server/cn=%u,dc=company,dc=com
2136
+	icap_auth_scheme WinNT://nt-domain/%u
2137
+	icap_auth_scheme Radius://radius-server/%u
2138
+DOC_END
2139
+
2140
+NAME: icap_service
2141
+TYPE: icap_service_type
2142
+IFDEF: HS_FEAT_ICAP
2143
+LOC: Config.icapcfg
2144
+DEFAULT: none
2145
+DOC_START
2146
+	Defines a single ICAP service
2147
+
2148
+	icap_service servicename vectoring_point bypass service_url [options ...]
2149
+
2150
+	vectoring_point = reqmod_precache|reqmod_postcache|respmod_precache|respmod_postcache
2151
+		This specifies at which point of request processing the ICAP
2152
+		service should be plugged in.
2153
+	bypass = 1|0   
2154
+		If set to 1 and the ICAP server cannot be reached, the request will go 
2155
+		through without being processed by an ICAP server
2156
+	service_url = icap://servername:port/service
2157
+
2158
+	Options: 
2159
+
2160
+        no-keep-alive	To always close the connection to icap server
2161
+        		after the transaction completes
2162
+
2163
+
2164
+	Note: reqmod_precache and respmod_postcache is not yet implemented
2165
+
2166
+	Load-balancing and high availability:
2167
+	You can obtain load-balancing and high availability by defining a
2168
+	named service with different definitions.  Then, the client
2169
+	loops through the different entities of the service providing
2170
+	load-balancing. If an entity is marked as unreachable, the client goes
2171
+	one step further to the next entity: you have the high-availability.
2172
+	See the service_1 definition below
2173
+
2174
+Example:
2175
+icap_service service_1 reqmod_precache 0 icap://icap1.mydomain.net:1344/reqmod
2176
+icap_service service_1 reqmod_precache 0 icap://icap2.mydomain.net:1344/reqmod no-keep-alive
2177
+icap_service service_2 respmod_precache 0 icap://icap3.mydomain.net:1344/respmod 
2178
+DOC_END
2179
+
2180
+NAME: icap_class
2181
+TYPE: icap_class_type
2182
+IFDEF: HS_FEAT_ICAP
2183
+LOC: Config.icapcfg
2184
+DEFAULT: none
2185
+DOC_START
2186
+	Defines an ICAP service chain. If there are multiple services per 
2187
+	vectoring point, they are processed in the specified order.
2188
+
2189
+	icap_class classname servicename...
2190
+
2191
+Example:
2192
+icap_class class_1 service_1 service_2
2193
+icap class class_2 service_1 service_3
2194
+DOC_END
2195
+
2196
+NAME: icap_access
2197
+TYPE: icap_access_type
2198
+IFDEF: HS_FEAT_ICAP
2199
+LOC: Config.icapcfg
2200
+DEFAULT: none
2201
+DOC_START
2202
+	Redirects a request through an ICAP service class, depending
2203
+	on given acls
2204
+
2205
+	icap_access classname allow|deny [!]aclname...
2206
+
2207
+	The icap_access statements are processed in the order they appear in
2208
+	this configuration file. If an access list matches, the processing stops. 
2209
+	For an "allow" rule, the specified class is used for the request. A "deny" 
2210
+	rule simply stops processing without using the class. You can also use the 
2211
+	special classname "None". 
2212
+	
2213
+	For backward compatibility, it is also possible to use services 
2214
+	directly here.
2215
+Example:
2216
+icap_access class_1 allow all
2217
+DOC_END
2218
+
2219
+COMMENT_START
2220
  MISCELLANEOUS
2221
  -----------------------------------------------------------------------------
2222
 COMMENT_END
2223
Index: src/cf_gen_defines
2224
===================================================================
2225
RCS file: /cvsroot/squid/squid/src/cf_gen_defines,v
2226
retrieving revision 1.5
2227
retrieving revision 1.5.48.3
2228
diff -p -u -b -r1.5 -r1.5.48.3
2229
--- src/cf_gen_defines	3 Dec 2001 08:03:21 -0000	1.5
2230
+++ src/cf_gen_defines	13 Mar 2005 17:58:44 -0000	1.5.48.3
2231
@@ -18,12 +18,13 @@ BEGIN {
2232
 	define["USE_UNLINKD"]="--enable-unlinkd"
2233
 	define["USE_USERAGENT_LOG"]="--enable-useragent-log"
2234
 	define["USE_WCCP"]="--enable-wccp"
2235
+	define["HS_FEAT_ICAP"]="--enable-icap-support"
2236
 }
2237
 /^IFDEF:/ {
2238
 	if (define[$2] != "")
2239
-	    DEFINE=define[$2]
2240
+	    DEFINE = define[$2]
2241
 	else  
2242
-	    DEFINE="-D" $2
2243
+	    DEFINE = "-D" $2
2244
 	print "{\"" $2 "\", \"" DEFINE "\", "
2245
 	print "#if " $2
2246
 	print "1"
2247
Index: src/client_side.c
2248
===================================================================
2249
RCS file: /cvsroot/squid/squid/src/client_side.c,v
2250
retrieving revision 1.47.2.76
2251
retrieving revision 1.47.2.28.2.41
2252
diff -p -u -b -r1.47.2.76 -r1.47.2.28.2.41
2253
--- src/client_side.c	11 Mar 2006 03:16:31 -0000	1.47.2.76
2254
+++ src/client_side.c	16 May 2006 17:56:58 -0000	1.47.2.28.2.41
2255
@@ -109,7 +109,7 @@ static const char *const crlf = "\r\n";
2256
 static CWCB clientWriteComplete;
2257
 static CWCB clientWriteBodyComplete;
2258
 static PF clientReadRequest;
2259
-static PF connStateFree;
2260
+PF connStateFree;
2261
 static PF requestTimeout;
2262
 static PF clientLifetimeTimeout;
2263
 static int clientCheckTransferDone(clientHttpRequest *);
2264
@@ -136,20 +136,23 @@ static void clientSetKeepaliveFlag(clien
2265
 static void clientPackRangeHdr(const HttpReply * rep, const HttpHdrRangeSpec * spec, String boundary, MemBuf * mb);
2266
 static void clientPackTermBound(String boundary, MemBuf * mb);
2267
 static void clientInterpretRequestHeaders(clientHttpRequest *);
2268
-static void clientProcessRequest(clientHttpRequest *);
2269
+void clientProcessRequest(clientHttpRequest *);
2270
 static void clientProcessExpired(void *data);
2271
 static void clientProcessOnlyIfCachedMiss(clientHttpRequest * http);
2272
-static int clientCachable(clientHttpRequest * http);
2273
-static int clientHierarchical(clientHttpRequest * http);
2274
-static int clientCheckContentLength(request_t * r);
2275
+int clientCachable(clientHttpRequest * http);
2276
+int clientHierarchical(clientHttpRequest * http);
2277
+int clientCheckContentLength(request_t * r);
2278
 static DEFER httpAcceptDefer;
2279
 static log_type clientProcessRequest2(clientHttpRequest * http);
2280
 static int clientReplyBodyTooLarge(clientHttpRequest *, squid_off_t clen);
2281
 static int clientRequestBodyTooLarge(squid_off_t clen);
2282
 static void clientProcessBody(ConnStateData * conn);
2283
 static void clientEatRequestBody(clientHttpRequest *);
2284
-static BODY_HANDLER clientReadBody;
2285
+BODY_HANDLER clientReadBody;
2286
 static void clientAbortBody(request_t * req);
2287
+#if HS_FEAT_ICAP
2288
+static int clientIcapReqMod(clientHttpRequest * http);
2289
+#endif
2290
 
2291
 static int
2292
 checkAccelOnly(clientHttpRequest * http)
2293
@@ -392,6 +395,10 @@ clientRedirectDone(void *data, char *res
2294
 	http->request = requestLink(new_request);
2295
     }
2296
     clientInterpretRequestHeaders(http);
2297
+#if HS_FEAT_ICAP
2298
+    if (Config.icapcfg.onoff)
2299
+	icapCheckAcl(http);
2300
+#endif
2301
 #if HEADERS_LOG
2302
     headersLog(0, 1, request->method, request);
2303
 #endif
2304
@@ -936,11 +943,22 @@ httpRequestFree(void *data)
2305
     *H = http->next;
2306
     http->next = NULL;
2307
     dlinkDelete(&http->active, &ClientActiveRequests);
2308
+#if HS_FEAT_ICAP
2309
+    /*In the case that the upload of data breaks, we need this code here ....  */
2310
+    if (NULL != http->icap_reqmod) {
2311
+	if (cbdataValid(http->icap_reqmod))
2312
+	    if (http->icap_reqmod->icap_fd > -1) {
2313
+		comm_close(http->icap_reqmod->icap_fd);
2314
+	    }
2315
+	cbdataUnlock(http->icap_reqmod);
2316
+	http->icap_reqmod = NULL;
2317
+    }
2318
+#endif
2319
     cbdataFree(http);
2320
 }
2321
 
2322
 /* This is a handler normally called by comm_close() */
2323
-static void
2324
+void
2325
 connStateFree(int fd, void *data)
2326
 {
2327
     ConnStateData *connState = data;
2328
@@ -963,7 +981,6 @@ connStateFree(int fd, void *data)
2329
     } else
2330
 	safe_free(connState->in.buf);
2331
     /* XXX account connState->in.buf */
2332
-    pconnHistCount(0, connState->nrequests);
2333
     cbdataFree(connState);
2334
 #ifdef _SQUID_LINUX_
2335
     /* prevent those nasty RST packets */
2336
@@ -1108,7 +1125,7 @@ clientSetKeepaliveFlag(clientHttpRequest
2337
     }
2338
 }
2339
 
2340
-static int
2341
+int
2342
 clientCheckContentLength(request_t * r)
2343
 {
2344
     switch (r->method) {
2345
@@ -1127,7 +1144,7 @@ clientCheckContentLength(request_t * r)
2346
     /* NOT REACHED */
2347
 }
2348
 
2349
-static int
2350
+int
2351
 clientCachable(clientHttpRequest * http)
2352
 {
2353
     request_t *req = http->request;
2354
@@ -1153,7 +1170,7 @@ clientCachable(clientHttpRequest * http)
2355
 }
2356
 
2357
 /* Return true if we can query our neighbors for this object */
2358
-static int
2359
+int
2360
 clientHierarchical(clientHttpRequest * http)
2361
 {
2362
     const char *url = http->uri;
2363
@@ -2447,7 +2464,7 @@ clientProcessRequest2(clientHttpRequest 
2364
     return LOG_TCP_HIT;
2365
 }
2366
 
2367
-static void
2368
+void
2369
 clientProcessRequest(clientHttpRequest * http)
2370
 {
2371
     char *url = http->uri;
2372
@@ -2457,6 +2474,11 @@ clientProcessRequest(clientHttpRequest *
2373
     debug(33, 4) ("clientProcessRequest: %s '%s'\n",
2374
 	RequestMethodStr[r->method],
2375
 	url);
2376
+#if HS_FEAT_ICAP
2377
+    if (clientIcapReqMod(http)) {
2378
+	return;
2379
+    }
2380
+#endif
2381
     if (r->method == METHOD_CONNECT && !http->redirect.status) {
2382
 	http->log_type = LOG_TCP_MISS;
2383
 	sslStart(http, &http->out.size, &http->al.http.code);
2384
@@ -3001,6 +3023,20 @@ clientReadRequest(int fd, void *data)
2385
 	    (long) conn->in.offset, (long) conn->in.size);
2386
 	len = conn->in.size - conn->in.offset - 1;
2387
     }
2388
+#if HS_FEAT_ICAP
2389
+    /*
2390
+     * This check exists because ICAP doesn't always work well
2391
+     * with persistent (reused) connections.  One version of the
2392
+     * REQMOD code creates a fake ConnStateData, which doesn't have
2393
+     * an in.buf.  We want to make sure that the fake ConnStateData
2394
+     * doesn't get used here.
2395
+     */
2396
+    if (NULL == conn->in.buf) {
2397
+	debug(33, 1) ("clientReadRequest: FD %d aborted; conn->in.buf is NULL\n", fd);
2398
+	comm_close(fd);
2399
+	return;
2400
+    }
2401
+#endif
2402
     statCounter.syscalls.sock.reads++;
2403
     size = FD_READ_METHOD(fd, conn->in.buf + conn->in.offset, len);
2404
     if (size > 0) {
2405
@@ -3104,7 +3140,8 @@ clientReadRequest(int fd, void *data)
2406
 	    /* add to the client request queue */
2407
 	    for (H = &conn->chr; *H; H = &(*H)->next);
2408
 	    *H = http;
2409
-	    conn->nrequests++;
2410
+	    F->pconn.uses++;
2411
+	    F->pconn.type = 0;
2412
 	    /*
2413
 	     * I wanted to lock 'http' here since its callback data for 
2414
 	     * clientLifetimeTimeout(), but there's no logical place to
2415
@@ -3274,7 +3311,7 @@ clientReadRequest(int fd, void *data)
2416
 }
2417
 
2418
 /* file_read like function, for reading body content */
2419
-static void
2420
+void
2421
 clientReadBody(request_t * request, char *buf, size_t size, CBCB * callback, void *cbdata)
2422
 {
2423
     ConnStateData *conn = request->body_reader_data;
2424
@@ -3398,7 +3435,7 @@ clientProcessBody(ConnStateData * conn)
2425
 }
2426
 
2427
 /* Abort a body request */
2428
-static void
2429
+void
2430
 clientAbortBody(request_t * request)
2431
 {
2432
     ConnStateData *conn = request->body_reader_data;
2433
@@ -3440,7 +3477,7 @@ requestTimeout(int fd, void *data)
2434
 	 * Some data has been sent to the client, just close the FD
2435
 	 */
2436
 	comm_close(fd);
2437
-    } else if (conn->nrequests) {
2438
+    } else if (fd_table[fd].pconn.uses) {
2439
 	/*
2440
 	 * assume its a persistent connection; just close it
2441
 	 */
2442
@@ -3956,3 +3993,49 @@ varyEvaluateMatch(StoreEntry * entry, re
2443
 	}
2444
     }
2445
 }
2446
+
2447
+#if HS_FEAT_ICAP
2448
+static int
2449
+clientIcapReqMod(clientHttpRequest * http)
2450
+{
2451
+    ErrorState *err;
2452
+    icap_service *service;
2453
+    if (http->flags.did_icap_reqmod)
2454
+	return 0;
2455
+    if (NULL == (service = icapService(ICAP_SERVICE_REQMOD_PRECACHE, http->request)))
2456
+	return 0;
2457
+    debug(33, 3) ("clientIcapReqMod: calling icapReqModStart for %p\n", http);
2458
+    /*
2459
+     * Note, we pass 'start' and 'log_addr' to ICAP so the access.log
2460
+     * entry comes out right.  The 'clientHttpRequest' created by
2461
+     * the ICAP side is the one that gets logged.  The first
2462
+     * 'clientHttpRequest' does not get logged because its out.size
2463
+     * is zero and log_type is unset.
2464
+     */
2465
+    http->icap_reqmod = icapReqModStart(service,
2466
+	http->uri,
2467
+	http->request,
2468
+	http->conn->fd,
2469
+	http->start,
2470
+	http->conn->log_addr,
2471
+	(void *) http->conn);
2472
+    if (NULL == http->icap_reqmod) {
2473
+	return 0;
2474
+    } else if (-1 == (int) http->icap_reqmod) {
2475
+	/* produce error */
2476
+	http->icap_reqmod = NULL;
2477
+	debug(33, 2) ("clientIcapReqMod: icap told us to send an error\n");
2478
+	http->log_type = LOG_TCP_DENIED;
2479
+	err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
2480
+	err->xerrno = ETIMEDOUT;
2481
+	err->request = requestLink(http->request);
2482
+	err->src_addr = http->conn->peer.sin_addr;
2483
+	http->entry = clientCreateStoreEntry(http, http->request->method, null_request_flags);
2484
+	errorAppendEntry(http->entry, err);
2485
+	return 1;
2486
+    }
2487
+    cbdataLock(http->icap_reqmod);
2488
+    http->flags.did_icap_reqmod = 1;
2489
+    return 1;
2490
+}
2491
+#endif
2492
Index: src/comm.c
2493
===================================================================
2494
RCS file: /cvsroot/squid/squid/src/comm.c,v
2495
retrieving revision 1.18.6.6
2496
retrieving revision 1.18.6.2.12.9
2497
diff -p -u -b -r1.18.6.6 -r1.18.6.2.12.9
2498
--- src/comm.c	11 Sep 2005 02:13:22 -0000	1.18.6.6
2499
+++ src/comm.c	23 Nov 2005 20:33:06 -0000	1.18.6.2.12.9
2500
@@ -653,8 +653,8 @@ comm_close(int fd)
2501
 #endif
2502
     CommWriteStateCallbackAndFree(fd, COMM_ERR_CLOSING);
2503
     commCallCloseHandlers(fd);
2504
-    if (F->uses)		/* assume persistent connect count */
2505
-	pconnHistCount(1, F->uses);
2506
+    if (F->pconn.uses)
2507
+	pconnHistCount(F->pconn.type, F->pconn.uses);
2508
 #if USE_SSL
2509
     if (F->ssl) {
2510
 	SSL_free(F->ssl);
2511
Index: src/enums.h
2512
===================================================================
2513
RCS file: /cvsroot/squid/squid/src/enums.h,v
2514
retrieving revision 1.29.2.18
2515
retrieving revision 1.29.2.8.2.17
2516
diff -p -u -b -r1.29.2.18 -r1.29.2.8.2.17
2517
--- src/enums.h	12 Nov 2005 03:13:48 -0000	1.29.2.18
2518
+++ src/enums.h	23 Nov 2005 20:38:56 -0000	1.29.2.8.2.17
2519
@@ -93,6 +93,7 @@ typedef enum {
2520
     ERR_ONLY_IF_CACHED_MISS,	/* failure to satisfy only-if-cached request */
2521
     ERR_TOO_BIG,
2522
     TCP_RESET,
2523
+    ERR_ICAP_FAILURE,
2524
     ERR_INVALID_RESP,
2525
     ERR_MAX
2526
 } err_type;
2527
@@ -438,6 +439,9 @@ typedef enum {
2528
     PROTO_WHOIS,
2529
     PROTO_INTERNAL,
2530
     PROTO_HTTPS,
2531
+#if HS_FEAT_ICAP
2532
+    PROTO_ICAP,
2533
+#endif
2534
     PROTO_MAX
2535
 } protocol_t;
2536
 
2537
@@ -610,6 +614,12 @@ typedef enum {
2538
     MEM_TLV,
2539
     MEM_SWAP_LOG_DATA,
2540
     MEM_CLIENT_REQ_BUF,
2541
+#if HS_FEAT_ICAP
2542
+    MEM_ICAP_OPT_DATA,
2543
+    MEM_ICAP_SERVICE_LIST,
2544
+    MEM_ICAP_CLASS,
2545
+    MEM_ICAP_ACCESS,
2546
+#endif
2547
     MEM_MAX
2548
 } mem_type;
2549
 
2550
@@ -709,9 +719,14 @@ typedef enum {
2551
     CBDATA_RemovalPolicyWalker,
2552
     CBDATA_RemovalPurgeWalker,
2553
     CBDATA_store_client,
2554
+#ifdef HS_FEAT_ICAP
2555
+    CBDATA_IcapStateData,
2556
+    CBDATA_icap_service,
2557
+#endif
2558
     CBDATA_FIRST_CUSTOM_TYPE = 1000
2559
 } cbdata_type;
2560
 
2561
+
2562
 /*
2563
  * Return codes from checkVary(request)
2564
  */
2565
@@ -742,4 +757,68 @@ enum {
2566
 
2567
 #endif
2568
 
2569
+#if HS_FEAT_ICAP
2570
+typedef enum {
2571
+    ICAP_STATUS_NONE = 0,
2572
+    ICAP_STATUS_CONTINUE = 100,
2573
+    ICAP_STATUS_SWITCHING_PROTOCOLS = 101,
2574
+    ICAP_STATUS_STATUS_OK = 200,
2575
+    ICAP_CREATED = 201,
2576
+    ICAP_STATUS_ACCEPTED = 202,
2577
+    ICAP_STATUS_NON_AUTHORITATIVE_INFORMATION = 203,
2578
+    ICAP_STATUS_NO_MODIFICATION_NEEDED = 204,
2579
+    ICAP_STATUS_RESET_CONTENT = 205,
2580
+    ICAP_STATUS_PARTIAL_CONTENT = 206,
2581
+    ICAP_STATUS_MULTIPLE_CHOICES = 300,
2582
+    ICAP_STATUS_MOVED_PERMANENTLY = 301,
2583
+    ICAP_STATUS_MOVED_TEMPORARILY = 302,
2584
+    ICAP_STATUS_SEE_OTHER = 303,
2585
+    ICAP_STATUS_NOT_MODIFIED = 304,
2586
+    ICAP_STATUS_USE_PROXY = 305,
2587
+    ICAP_STATUS_BAD_REQUEST = 400,
2588
+    ICAP_STATUS_UNAUTHORIZED = 401,
2589
+    ICAP_STATUS_PAYMENT_REQUIRED = 402,
2590
+    ICAP_STATUS_FORBIDDEN = 403,
2591
+    ICAP_STATUS_SERVICE_NOT_FOUND = 404,
2592
+    ICAP_STATUS_METHOD_NOT_ALLOWED = 405,
2593
+    ICAP_STATUS_NOT_ACCEPTABLE = 406,
2594
+    ICAP_STATUS_PROXY_AUTHENTICATION_REQUIRED = 407,
2595
+    ICAP_STATUS_REQUEST_TIMEOUT = 408,
2596
+    ICAP_STATUS_CONFLICT = 409,
2597
+    ICAP_STATUS_GONE = 410,
2598
+    ICAP_STATUS_LENGTH_REQUIRED = 411,
2599
+    ICAP_STATUS_PRECONDITION_FAILED = 412,
2600
+    ICAP_STATUS_REQUEST_ENTITY_TOO_LARGE = 413,
2601
+    ICAP_STATUS_REQUEST_URI_TOO_LARGE = 414,
2602
+    ICAP_STATUS_UNSUPPORTED_MEDIA_TYPE = 415,
2603
+    ICAP_STATUS_INTERNAL_SERVER_ERROR = 500,
2604
+    ICAP_STATUS_NOT_IMPLEMENTED = 501,
2605
+    ICAP_STATUS_BAD_GATEWAY = 502,
2606
+    ICAP_STATUS_SERVICE_OVERLOADED = 503,
2607
+    ICAP_STATUS_GATEWAY_TIMEOUT = 504,
2608
+    ICAP_STATUS_ICAP_VERSION_NOT_SUPPORTED = 505,
2609
+    ICAP_STATUS_INVALID_HEADER = 600
2610
+} icap_status;
2611
+
2612
+/*
2613
+ * these values are used as index in an array, so it seems to be better to 
2614
+ * assign some numbers
2615
+ */
2616
+typedef enum {
2617
+    ICAP_SERVICE_REQMOD_PRECACHE = 0,
2618
+    ICAP_SERVICE_REQMOD_POSTCACHE = 1,
2619
+    ICAP_SERVICE_RESPMOD_PRECACHE = 2,
2620
+    ICAP_SERVICE_RESPMOD_POSTCACHE = 3,
2621
+    ICAP_SERVICE_MAX = 4
2622
+} icap_service_t;
2623
+
2624
+typedef enum {
2625
+    ICAP_METHOD_NONE,
2626
+    ICAP_METHOD_OPTION,
2627
+    ICAP_METHOD_REQMOD,
2628
+    ICAP_METHOD_RESPMOD
2629
+} icap_method_t;
2630
+
2631
+#endif /* HS_FEAT_ICAP */
2632
+
2633
 #endif /* SQUID_ENUMS_H */
2634
Index: src/forward.c
2635
===================================================================
2636
RCS file: /cvsroot/squid/squid/src/forward.c,v
2637
retrieving revision 1.13.6.16
2638
retrieving revision 1.13.6.3.2.16
2639
diff -p -u -b -r1.13.6.16 -r1.13.6.3.2.16
2640
--- src/forward.c	11 Mar 2006 03:16:31 -0000	1.13.6.16
2641
+++ src/forward.c	16 May 2006 17:56:58 -0000	1.13.6.3.2.16
2642
@@ -251,7 +251,8 @@ fwdConnectDone(int server_fd, int status
2643
     } else {
2644
 	debug(17, 3) ("fwdConnectDone: FD %d: '%s'\n", server_fd, storeUrl(fwdState->entry));
2645
 	fd_note(server_fd, storeUrl(fwdState->entry));
2646
-	fd_table[server_fd].uses++;
2647
+	fd_table[server_fd].pconn.uses++;
2648
+	fd_table[server_fd].pconn.type = 1;
2649
 	if (fs->peer)
2650
 	    peerConnectSucceded(fs->peer);
2651
 	fwdDispatch(fwdState);
2652
@@ -700,6 +701,8 @@ fwdCheckDeferRead(int fd, void *data)
2653
 void
2654
 fwdFail(FwdState * fwdState, ErrorState * errorState)
2655
 {
2656
+    if (NULL == fwdState)
2657
+	return;
2658
     debug(17, 3) ("fwdFail: %s \"%s\"\n\t%s\n",
2659
 	err_type_str[errorState->type],
2660
 	httpStatusString(errorState->http_status),
2661
@@ -738,6 +741,8 @@ fwdPeerClosed(int fd, void *data)
2662
 void
2663
 fwdUnregister(int fd, FwdState * fwdState)
2664
 {
2665
+    if (NULL == fwdState)
2666
+	return;
2667
     debug(17, 3) ("fwdUnregister: %s\n", storeUrl(fwdState->entry));
2668
     assert(fd == fwdState->server_fd);
2669
     assert(fd > -1);
2670
@@ -754,7 +759,10 @@ fwdUnregister(int fd, FwdState * fwdStat
2671
 void
2672
 fwdComplete(FwdState * fwdState)
2673
 {
2674
-    StoreEntry *e = fwdState->entry;
2675
+    StoreEntry *e;
2676
+    if (NULL == fwdState)
2677
+	return;
2678
+    e = fwdState->entry;
2679
     assert(e->store_status == STORE_PENDING);
2680
     debug(17, 3) ("fwdComplete: %s\n\tstatus %d\n", storeUrl(e),
2681
 	e->mem_obj->reply->sline.status);
2682
Index: src/globals.h
2683
===================================================================
2684
RCS file: /cvsroot/squid/squid/src/globals.h,v
2685
retrieving revision 1.14.6.7
2686
retrieving revision 1.14.6.3.2.5
2687
diff -p -u -b -r1.14.6.7 -r1.14.6.3.2.5
2688
--- src/globals.h	14 Jun 2005 02:15:00 -0000	1.14.6.7
2689
+++ src/globals.h	12 Sep 2005 18:34:41 -0000	1.14.6.3.2.5
2690
@@ -165,6 +165,9 @@ extern char *WIN32_OS_string;	/* NULL */
2691
 #if HAVE_SBRK
2692
 extern void *sbrk_start;	/* 0 */
2693
 #endif
2694
+#if HS_FEAT_ICAP
2695
+extern char *icap_service_type_str[];
2696
+#endif
2697
 extern int opt_send_signal;	/* -1 */
2698
 extern int opt_no_daemon;	/* 0 */
2699
 
2700
Index: src/http.c
2701
===================================================================
2702
RCS file: /cvsroot/squid/squid/src/http.c,v
2703
retrieving revision 1.17.6.32
2704
retrieving revision 1.17.6.3.6.40
2705
diff -p -u -b -r1.17.6.32 -r1.17.6.3.6.40
2706
--- src/http.c	19 Oct 2005 02:13:21 -0000	1.17.6.32
2707
+++ src/http.c	17 Feb 2006 12:45:21 -0000	1.17.6.3.6.40
2708
@@ -47,7 +47,7 @@ static CWCB httpSendRequestEntry;
2709
 
2710
 static PF httpReadReply;
2711
 static void httpSendRequest(HttpStateData *);
2712
-static PF httpStateFree;
2713
+PF httpStateFree;
2714
 static PF httpTimeout;
2715
 static void httpCacheNegatively(StoreEntry *);
2716
 static void httpMakePrivate(StoreEntry *);
2717
@@ -55,11 +55,12 @@ static void httpMakePublic(StoreEntry *)
2718
 static int httpCachableReply(HttpStateData *);
2719
 static void httpMaybeRemovePublic(StoreEntry *, http_status);
2720
 
2721
-static void
2722
+void
2723
 httpStateFree(int fd, void *data)
2724
 {
2725
     HttpStateData *httpState = data;
2726
 #if DELAY_POOLS
2727
+    if (fd >= 0)
2728
     delayClearNoDelay(fd);
2729
 #endif
2730
     if (httpState == NULL)
2731
@@ -79,6 +80,9 @@ httpStateFree(int fd, void *data)
2732
     requestUnlink(httpState->orig_request);
2733
     httpState->request = NULL;
2734
     httpState->orig_request = NULL;
2735
+#if HS_FEAT_ICAP
2736
+    cbdataUnlock(httpState->icap_writer);
2737
+#endif
2738
     cbdataFree(httpState);
2739
 }
2740
 
2741
@@ -392,7 +396,7 @@ httpMakeVaryMark(request_t * request, Ht
2742
 }
2743
 
2744
 /* rewrite this later using new interfaces @?@ */
2745
-static void
2746
+void
2747
 httpProcessReplyHeader(HttpStateData * httpState, const char *buf, int size)
2748
 {
2749
     StoreEntry *entry = httpState->entry;
2750
@@ -527,24 +531,35 @@ httpPconnTransferDone(HttpStateData * ht
2751
     MemObject *mem = httpState->entry->mem_obj;
2752
     HttpReply *reply = mem->reply;
2753
     squid_off_t clen;
2754
+    squid_off_t content_bytes_read;
2755
     debug(11, 3) ("httpPconnTransferDone: FD %d\n", httpState->fd);
2756
     debug(11, 5) ("httpPconnTransferDone: content_length=%" PRINTF_OFF_T "\n",
2757
 	reply->content_length);
2758
     /* If we haven't seen the end of reply headers, we are not done */
2759
-    if (httpState->reply_hdr_state < 2)
2760
+    if (httpState->reply_hdr_state < 2) {
2761
+	debug(11, 3) ("httpPconnTransferDone: reply_hdr_state=%d, returning 0\n",
2762
+	    httpState->reply_hdr_state);
2763
 	return 0;
2764
+    }
2765
     clen = httpReplyBodySize(httpState->request->method, reply);
2766
+#ifdef HS_FEAT_ICAP
2767
+    if (httpState->icap_writer) {
2768
+	content_bytes_read = httpState->icap_writer->fake_content_length;
2769
+	debug(11, 3) ("using fake conten length %" PRINTF_OFF_T "\n", content_bytes_read);
2770
+    } else
2771
+#endif
2772
+	content_bytes_read = mem->inmem_hi;
2773
     /* If the body size is unknown we must wait for EOF */
2774
     if (clen < 0)
2775
 	return 0;
2776
     /* Barf if we got more than we asked for */
2777
-    if (mem->inmem_hi > clen + reply->hdr_sz)
2778
+    if (content_bytes_read > clen + reply->hdr_sz)
2779
 	return -1;
2780
     /* If there is no message body, we can be persistent */
2781
     if (0 == clen)
2782
 	return 1;
2783
     /* If the body size is known, we must wait until we've gotten all of it.  */
2784
-    if (mem->inmem_hi < clen + reply->hdr_sz)
2785
+    if (content_bytes_read < clen + reply->hdr_sz)
2786
 	return 0;
2787
     /* We got it all */
2788
     return 1;
2789
@@ -568,6 +583,17 @@ httpReadReply(int fd, void *data)
2790
     delay_id delay_id;
2791
 #endif
2792
 
2793
+#if HS_FEAT_ICAP
2794
+    if (httpState->icap_writer) {
2795
+	if (!httpState->icap_writer->respmod.entry) {
2796
+	    debug(11, 3) ("httpReadReply: FD: %d: icap respmod aborded!\n", fd);
2797
+	    comm_close(fd);
2798
+	    return;
2799
+	}
2800
+	/*The folowing entry can not be marked as aborted.  
2801
+	 * The StoreEntry icap_writer->respmod.entry used when the icap_write used...... */
2802
+    } else
2803
+#endif
2804
     if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
2805
 	comm_close(fd);
2806
 	return;
2807
@@ -579,6 +605,37 @@ httpReadReply(int fd, void *data)
2808
     else
2809
 	delay_id = delayMostBytesAllowed(entry->mem_obj, &read_sz);
2810
 #endif
2811
+
2812
+#if HS_FEAT_ICAP
2813
+    if (httpState->icap_writer) {
2814
+	IcapStateData *icap = httpState->icap_writer;
2815
+	/*
2816
+	 * Ok we have a received a response from the web server, so try to 
2817
+	 * connect the icap server if it's the first attemps. If we try
2818
+	 * to connect to the icap server, defer this request (do not read
2819
+	 * the buffer), and defer until icapConnectOver() is not called.
2820
+	 */
2821
+	if (icap->flags.connect_requested == 0) {
2822
+	    debug(81, 2) ("icapSendRespMod: Create a new connection to icap server\n");
2823
+	    if (!icapConnect(icap, icapConnectOver)) {
2824
+		debug(81, 2) ("icapSendRespMod: Something strange while creating a socket to icap server\n");
2825
+		commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
2826
+		return;
2827
+	    }
2828
+	    debug(81, 2) ("icapSendRespMod: new connection to icap server (using FD=%d)\n", icap->icap_fd);
2829
+	    icap->flags.connect_requested = 1;
2830
+	    /* Wait for more data or EOF condition */
2831
+	    commSetTimeout(fd, httpState->flags.keepalive_broken ? 10 : Config.Timeout.read, NULL, NULL);
2832
+	    commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
2833
+	    return;
2834
+	}
2835
+
2836
+       if(icap->flags.no_content == 1) {
2837
+	 commSetDefer(fd, fwdCheckDeferRead, icap->respmod.entry);
2838
+       }
2839
+    }
2840
+#endif
2841
+
2842
     errno = 0;
2843
     statCounter.syscalls.sock.reads++;
2844
     len = FD_READ_METHOD(fd, buf, read_sz);
2845
@@ -595,7 +652,13 @@ httpReadReply(int fd, void *data)
2846
 	    clen >>= 1;
2847
 	IOStats.Http.read_hist[bin]++;
2848
     }
2849
-    if (!httpState->reply_hdr.size && len > 0 && fd_table[fd].uses > 1) {
2850
+#ifdef HS_FEAT_ICAP
2851
+    if (httpState->icap_writer)
2852
+	(void) 0;
2853
+    else
2854
+#endif
2855
+
2856
+    if (!httpState->reply_hdr.size && len > 0 && fd_table[fd].pconn.uses > 1) {
2857
 	/* Skip whitespace */
2858
 	while (len > 0 && xisspace(*buf))
2859
 	    xmemmove(buf, buf + 1, len--);
2860
@@ -625,6 +688,12 @@ httpReadReply(int fd, void *data)
2861
     } else if (len == 0) {
2862
 	/* Connection closed; retrieval done. */
2863
 	httpState->eof = 1;
2864
+#ifdef HS_FEAT_ICAP
2865
+	if (httpState->icap_writer && cbdataValid(httpState->icap_writer)) {
2866
+	    debug(81, 3) ("httpReadReply: EOF for ICAP writer\n");
2867
+	    icapSendRespMod(httpState->icap_writer, buf, len, 1);
2868
+	}
2869
+#endif
2870
 	if (httpState->reply_hdr_state < 2)
2871
 	    /*
2872
 	     * Yes Henrik, there is a point to doing this.  When we
2873
@@ -677,7 +746,28 @@ httpReadReply(int fd, void *data)
2874
 		    EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
2875
 	    }
2876
 	}
2877
+#ifdef HS_FEAT_ICAP
2878
+	if (httpState->icap_writer) {
2879
+	    debug(81, 5) ("calling icapSendRespMod from %s:%d\n", __FILE__, __LINE__);
2880
+	    if (cbdataValid(httpState->icap_writer)) {
2881
+		icapSendRespMod(httpState->icap_writer, buf, len, 0);
2882
+		httpState->icap_writer->fake_content_length += len;
2883
+	    }
2884
+	} else
2885
+#endif
2886
 	storeAppend(entry, buf, len);
2887
+
2888
+
2889
+	debug(11, 5) ("httpReadReply: after storeAppend FD %d read %d\n", fd, len);
2890
+#if HS_FEAT_ICAP
2891
+	if (httpState->icap_writer) {
2892
+	    if (!httpState->icap_writer->respmod.entry) {
2893
+		debug(11, 3) ("httpReadReply: FD: %d: icap respmod aborded!\n", fd);
2894
+		comm_close(fd);
2895
+		return;
2896
+	    }
2897
+	} else
2898
+#endif
2899
 	if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
2900
 	    /*
2901
 	     * the above storeAppend() call could ABORT this entry,
2902
@@ -724,10 +814,21 @@ httpReadReply(int fd, void *data)
2903
 			    ("httpReadReply: Excess data from \"%s %s\"\n",
2904
 			    RequestMethodStr[httpState->orig_request->method],
2905
 			    storeUrl(entry));
2906
+#ifdef HS_FEAT_ICAP
2907
+			if (httpState->icap_writer) {
2908
+			    debug(81, 5) ("calling icapSendRespMod from %s:%d\n", __FILE__, __LINE__);
2909
+			    icapSendRespMod(httpState->icap_writer, buf, len, 0);
2910
+			    httpState->icap_writer->fake_content_length += len;
2911
+			} else
2912
+#endif
2913
 			storeAppend(entry, buf, len);
2914
 			keep_alive = 0;
2915
 		    }
2916
 		}
2917
+#ifdef HS_FEAT_ICAP
2918
+		if (httpState->icap_writer)
2919
+		    icapSendRespMod(httpState->icap_writer, NULL, 0, 1);
2920
+#endif
2921
 		if (keep_alive) {
2922
 		    /* yes we have to clear all these! */
2923
 		    commSetDefer(fd, NULL, NULL);
2924
@@ -766,6 +867,10 @@ httpReadReply(int fd, void *data)
2925
 		("httpReadReply: Excess data from \"%s %s\"\n",
2926
 		RequestMethodStr[httpState->orig_request->method],
2927
 		storeUrl(entry));
2928
+#ifdef HS_FEAT_ICAP
2929
+	    if (httpState->icap_writer)
2930
+		icapSendRespMod(httpState->icap_writer, NULL, 0, 1);
2931
+#endif
2932
 	    fwdComplete(httpState->fwd);
2933
 	    comm_close(fd);
2934
 	    return;
2935
@@ -776,6 +881,34 @@ httpReadReply(int fd, void *data)
2936
     }
2937
 }
2938
 
2939
+#ifdef HS_FEAT_ICAP
2940
+static int
2941
+httpReadReplyWaitForIcap(int fd, void *data)
2942
+{
2943
+    HttpStateData *httpState = data;
2944
+    if (NULL == httpState->icap_writer)
2945
+	return 0;
2946
+    /* 
2947
+     * Do not defer when we are not connected to the icap server.
2948
+     * Defer when the icap server connection is not established but pending
2949
+     * Defer when the icap server is busy (writing on the socket)
2950
+     */
2951
+    debug(11, 5) ("httpReadReplyWaitForIcap: FD %d, connect_requested=%d\n",
2952
+	fd, httpState->icap_writer->flags.connect_requested);
2953
+    if (!httpState->icap_writer->flags.connect_requested)
2954
+	return 0;
2955
+    debug(11, 5) ("httpReadReplyWaitForIcap: FD %d, connect_pending=%d\n",
2956
+	fd, httpState->icap_writer->flags.connect_pending);
2957
+    if (httpState->icap_writer->flags.connect_pending)
2958
+	return 1;
2959
+    debug(11, 5) ("httpReadReplyWaitForIcap: FD %d, write_pending=%d\n",
2960
+	fd, httpState->icap_writer->flags.write_pending);
2961
+    if (httpState->icap_writer->flags.write_pending)
2962
+	return 1;
2963
+    return 0;
2964
+}
2965
+#endif
2966
+
2967
 /* This will be called when request write is complete. Schedule read of
2968
  * reply. */
2969
 static void
2970
@@ -803,6 +936,63 @@ httpSendComplete(int fd, char *bufnotuse
2971
 	comm_close(fd);
2972
 	return;
2973
     } else {
2974
+	/* Schedule read reply. */
2975
+#ifdef HS_FEAT_ICAP
2976
+	if (icapService(ICAP_SERVICE_RESPMOD_PRECACHE, httpState->orig_request)) {
2977
+	    httpState->icap_writer = icapRespModStart(
2978
+		ICAP_SERVICE_RESPMOD_PRECACHE,
2979
+		httpState->orig_request, httpState->entry, httpState->flags);
2980
+	    if (-1 == (int) httpState->icap_writer) {
2981
+		/* TODO: send error here and exit */
2982
+		ErrorState *err;
2983
+		httpState->icap_writer = 0;
2984
+		err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
2985
+		err->xerrno = errno;
2986
+		err->request = requestLink(httpState->orig_request);
2987
+		errorAppendEntry(entry, err);
2988
+		comm_close(fd);
2989
+		return;
2990
+	    } else if (httpState->icap_writer) {
2991
+		request_flags fake_flags = httpState->orig_request->flags;
2992
+		method_t fake_method = entry->mem_obj->method;
2993
+		const char *fake_msg = "this is a fake entry for "
2994
+		" response sent to an ICAP RESPMOD server";
2995
+		cbdataLock(httpState->icap_writer);
2996
+		/*
2997
+		 * this httpState will give the data it reads to
2998
+		 * the icap server, rather than put it into
2999
+		 * a StoreEntry
3000
+		 */
3001
+		storeUnlockObject(httpState->entry);
3002
+		storeUnregisterAbort(httpState->entry);
3003
+		/*
3004
+		 * create a bogus entry because the code assumes one is
3005
+		 * always there.
3006
+		 */
3007
+		fake_flags.cachable = 0;
3008
+		fake_flags.hierarchical = 0;	/* force private key */
3009
+		httpState->entry = storeCreateEntry("fake", "fake", fake_flags, fake_method);
3010
+		storeAppend(httpState->entry, fake_msg, strlen(fake_msg));
3011
+		/*
3012
+		 * pull a switcheroo on fwdState->entry.
3013
+		 */
3014
+		storeUnlockObject(httpState->fwd->entry);
3015
+		httpState->fwd->entry = httpState->entry;
3016
+		storeLockObject(httpState->fwd->entry);
3017
+		/*
3018
+		 * Note that we leave fwdState connected to httpState,
3019
+		 * but we changed the entry.  So when fwdComplete
3020
+		 * or whatever is called it does no harm -- its
3021
+		 * just the fake entry.
3022
+		 */
3023
+	    } else {
3024
+		/*
3025
+		 * failed to open connection to ICAP server. 
3026
+		 * But bypass request, so just continue here.
3027
+		 */
3028
+	    }
3029
+	}
3030
+#endif
3031
 	/*
3032
 	 * Set the read timeout here because it hasn't been set yet.
3033
 	 * We only set the read timeout after the request has been
3034
@@ -811,8 +1001,18 @@ httpSendComplete(int fd, char *bufnotuse
3035
 	 * the timeout for POST/PUT requests that have very large
3036
 	 * request bodies.
3037
 	 */
3038
+
3039
+	/* removed in stable5:
3040
+	 * commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
3041
+	 */
3042
 	commSetTimeout(fd, Config.Timeout.read, httpTimeout, httpState);
3043
-	commSetDefer(fd, fwdCheckDeferRead, entry);
3044
+#ifdef HS_FEAT_ICAP
3045
+	if (httpState->icap_writer) {
3046
+	    debug(11, 5) ("FD %d, setting httpReadReplyWaitForIcap\n", httpState->fd);
3047
+	    commSetDefer(httpState->fd, httpReadReplyWaitForIcap, httpState);
3048
+	} else
3049
+#endif
3050
+	    commSetDefer(httpState->fd, fwdCheckDeferRead, entry);
3051
     }
3052
     httpState->flags.request_sent = 1;
3053
 }
3054
@@ -1010,8 +1210,11 @@ httpBuildRequestHeader(request_t * reque
3055
 	if (!EBIT_TEST(cc->mask, CC_MAX_AGE)) {
3056
 	    const char *url = entry ? storeUrl(entry) : urlCanonical(orig_request);
3057
 	    httpHdrCcSetMaxAge(cc, getMaxAge(url));
3058
+#ifndef HS_FEAT_ICAP
3059
+	    /* Don;t bother - if  the url you want to cache is redirected? */
3060
 	    if (strLen(request->urlpath))
3061
 		assert(strstr(url, strBuf(request->urlpath)));
3062
+#endif
3063
 	}
3064
 	/* Set no-cache if determined needed but not found */
3065
 	if (orig_request->flags.nocache && !httpHeaderHas(hdr_in, HDR_PRAGMA))
3066
@@ -1119,6 +1322,7 @@ httpStart(FwdState * fwd)
3067
     int fd = fwd->server_fd;
3068
     HttpStateData *httpState;
3069
     request_t *proxy_req;
3070
+    /* ErrorState *err; */
3071
     request_t *orig_req = fwd->request;
3072
     debug(11, 3) ("httpStart: \"%s %s\"\n",
3073
 	RequestMethodStr[orig_req->method],
3074
@@ -1156,12 +1360,22 @@ httpStart(FwdState * fwd)
3075
 	httpState->request = requestLink(orig_req);
3076
 	httpState->orig_request = requestLink(orig_req);
3077
     }
3078
+#ifdef HS_FEAT_ICAP
3079
+    if (icapService(ICAP_SERVICE_REQMOD_POSTCACHE, httpState->orig_request)) {
3080
+	httpState->icap_writer = icapRespModStart(ICAP_SERVICE_REQMOD_POSTCACHE,
3081
+	    httpState->orig_request, httpState->entry, httpState->flags);
3082
+	if (httpState->icap_writer) {
3083
+	    return;
3084
+	}
3085
+    }
3086
+#endif
3087
     /*
3088
      * register the handler to free HTTP state data when the FD closes
3089
      */
3090
     comm_add_close_handler(fd, httpStateFree, httpState);
3091
     statCounter.server.all.requests++;
3092
     statCounter.server.http.requests++;
3093
+
3094
     httpSendRequest(httpState);
3095
     /*
3096
      * We used to set the read timeout here, but not any more.
3097
Index: src/icap_common.c
3098
===================================================================
3099
RCS file: src/icap_common.c
3100
diff -N src/icap_common.c
3101
--- /dev/null	1 Jan 1970 00:00:00 -0000
3102
+++ src/icap_common.c	16 Feb 2006 17:21:45 -0000	1.1.2.40
3103
@@ -0,0 +1,817 @@
3104
+/*
3105
+ * $Id$
3106
+ *
3107
+ * DEBUG: section 81    Internet Content Adaptation Protocol (ICAP) Client
3108
+ * AUTHOR: Geetha Manjunath, Hewlett Packard Company
3109
+ *
3110
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
3111
+ * ----------------------------------------------------------
3112
+ *
3113
+ *  Squid is the result of efforts by numerous individuals from
3114
+ *  the Internet community; see the CONTRIBUTORS file for full
3115
+ *  details.   Many organizations have provided support for Squid's
3116
+ *  development; see the SPONSORS file for full details.  Squid is
3117
+ *  Copyrighted (C) 2001 by the Regents of the University of
3118
+ *  California; see the COPYRIGHT file for full details.  Squid
3119
+ *  incorporates software developed and/or copyrighted by other
3120
+ *  sources; see the CREDITS file for full details.
3121
+ *
3122
+ *  This program is free software; you can redistribute it and/or modify
3123
+ *  it under the terms of the GNU General Public License as published by
3124
+ *  the Free Software Foundation; either version 2 of the License, or
3125
+ *  (at your option) any later version.
3126
+ *  
3127
+ *  This program is distributed in the hope that it will be useful,
3128
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
3129
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
3130
+ *  GNU General Public License for more details.
3131
+ *  
3132
+ *  You should have received a copy of the GNU General Public License
3133
+ *  along with this program; if not, write to the Free Software
3134
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
3135
+ *
3136
+ */
3137
+
3138
+/* _GNU_SOURCE is required for strcasestr */
3139
+#define _GNU_SOURCE 1
3140
+
3141
+#include "squid.h"
3142
+#include "util.h"
3143
+
3144
+extern PF httpStateFree;
3145
+
3146
+#define EXPECTED_ICAP_HEADER_LEN 256
3147
+#define ICAP_OPTIONS_REQUEST
3148
+
3149
+
3150
+void
3151
+icapInit()
3152
+{
3153
+#ifdef ICAP_OPTIONS_REQUEST
3154
+    if (Config.icapcfg.onoff) {
3155
+	icapOptInit();
3156
+    }
3157
+#endif
3158
+}
3159
+
3160
+void
3161
+icapClose()
3162
+{
3163
+    icapOptShutdown();
3164
+}
3165
+
3166
+/*
3167
+ * search for a HTTP-like header in the buffer. 
3168
+ * Note, buf must be 0-terminated
3169
+ *
3170
+ * This function is not very good.  It should probably look for
3171
+ * header tokens only at the start of a line, not just anywhere in
3172
+ * the buffer.
3173
+ */
3174
+int
3175
+icapFindHeader(const char *buf, const char *hdr, const char **Start,
3176
+    const char **End)
3177
+{
3178
+    const char *start = NULL;
3179
+    const char *end = NULL;
3180
+    start = strcasestr(buf, hdr);
3181
+    if (NULL == start)
3182
+	return 0;
3183
+    end = start + strcspn(start, "\r\n");
3184
+    if (start == end)
3185
+	return 0;
3186
+    *Start = start;
3187
+    *End = end;
3188
+    return 1;
3189
+}
3190
+
3191
+/* 
3192
+ * parse the contents of the encapsulated header (buffer between enc_start
3193
+ * and enc_end) and put the result into IcapStateData
3194
+ */
3195
+void
3196
+icapParseEncapsulated(IcapStateData * icap, const char *enc_start,
3197
+    const char *enc_end)
3198
+{
3199
+    char *current, *end;
3200
+
3201
+    assert(icap);
3202
+    assert(enc_start);
3203
+    assert(enc_end);
3204
+
3205
+    current = strchr(enc_start, ':');
3206
+    current++;
3207
+    while (current < enc_end) {
3208
+	while (isspace(*current))
3209
+	    current++;
3210
+	if (!strncmp(current, "res-hdr=", 8)) {
3211
+	    current += 8;
3212
+	    icap->enc.res_hdr = strtol(current, &end, 10);
3213
+	} else if (!strncmp(current, "req-hdr=", 8)) {
3214
+	    current += 8;
3215
+	    icap->enc.req_hdr = strtol(current, &end, 10);
3216
+	} else if (!strncmp(current, "null-body=", 10)) {
3217
+	    current += 10;
3218
+	    icap->enc.null_body = strtol(current, &end, 10);
3219
+	} else if (!strncmp(current, "res-body=", 9)) {
3220
+	    current += 9;
3221
+	    icap->enc.res_body = strtol(current, &end, 10);
3222
+	} else if (!strncmp(current, "req-body=", 9)) {
3223
+	    current += 9;
3224
+	    icap->enc.req_body = strtol(current, &end, 10);
3225
+	} else if (!strncmp(current, "opt-body=", 9)) {
3226
+	    current += 9;
3227
+	    icap->enc.opt_body = strtol(current, &end, 10);
3228
+	} else {
3229
+	    /* invalid header */
3230
+	    debug(81, 5) ("icapParseEncapsulated: error in: %s\n", current);
3231
+	    return;
3232
+	}
3233
+	current = end;
3234
+	current = strchr(current, ',');
3235
+	if (current == NULL)
3236
+	    break;
3237
+	else
3238
+	    current++;		/* skip ',' */
3239
+    }
3240
+    debug(81,
3241
+	3) ("icapParseEncapsulated: res-hdr=%d, req-hdr=%d, null-body=%d, "
3242
+	"res-body=%d, req-body=%d, opt-body=%d\n", icap->enc.res_hdr,
3243
+	icap->enc.req_hdr, icap->enc.null_body, icap->enc.res_body,
3244
+	icap->enc.req_body, icap->enc.opt_body);
3245
+
3246
+}
3247
+
3248
+icap_service *
3249
+icapService(icap_service_t type, request_t * r)
3250
+{
3251
+    icap_service_list *isl_iter;
3252
+    int is_iter;
3253
+    int nb_unreachable = 0;
3254
+    icap_service *unreachable_one = NULL;
3255
+
3256
+    debug(81, 8) ("icapService: type=%s\n", icapServiceToStr(type));
3257
+    if (NULL == r) {
3258
+	debug(81, 8) ("icapService: no request_t\n");
3259
+	return NULL;
3260
+    }
3261
+    if (NULL == r->class) {
3262
+	debug(81, 8) ("icapService: no class\n");
3263
+	return NULL;
3264
+    }
3265
+    for (isl_iter = r->class->isl; isl_iter; isl_iter = isl_iter->next) {
3266
+	/* TODO:luc: Do a round-robin, choose a random value ? 
3267
+	 * For now, we use a simple round robin with checking is the
3268
+	 * icap server is available */
3269
+	is_iter = isl_iter->last_service_used;
3270
+	do {
3271
+	    is_iter = (is_iter + 1) % isl_iter->nservices;
3272
+	    debug(81, 8) ("icapService: checking service %s/id=%d\n",
3273
+		isl_iter->services[is_iter]->name, is_iter);
3274
+	    if (type == isl_iter->services[is_iter]->type) {
3275
+		if (!isl_iter->services[is_iter]->unreachable) {
3276
+		    debug(81, 8) ("icapService: found service %s/id=%d\n",
3277
+			isl_iter->services[is_iter]->name, is_iter);
3278
+		    isl_iter->last_service_used = is_iter;
3279
+		    return isl_iter->services[is_iter];
3280
+		}
3281
+		debug(81,
3282
+		    8)
3283
+		    ("icapService: found service %s/id=%d, but it's unreachable. I don't want to use it\n",
3284
+		    isl_iter->services[is_iter]->name, is_iter);
3285
+		unreachable_one = isl_iter->services[is_iter];
3286
+		nb_unreachable++;
3287
+		/* FIXME:luc: in response mod, if we return an NULL pointer, user can bypass
3288
+		 * the filter, is it normal ? */
3289
+	    }
3290
+	} while (is_iter != isl_iter->last_service_used);
3291
+    }
3292
+    debug(81, 8) ("icapService: no service found\n");
3293
+    isl_iter = r->class->isl;
3294
+
3295
+    if (nb_unreachable > 0) {
3296
+	debug(81,
3297
+	    8)
3298
+	    ("All the services are unreachable, returning an unreachable one\n");
3299
+	return unreachable_one;
3300
+    } else {
3301
+	return NULL;
3302
+    }
3303
+}
3304
+
3305
+int
3306
+icapConnect(IcapStateData * icap, CNCB * theCallback)
3307
+{
3308
+    int rc;
3309
+    icap->icap_fd = pconnPop(icap->current_service->hostname,
3310
+	icap->current_service->port);
3311
+    if (icap->icap_fd >= 0) {
3312
+	debug(81, 3) ("icapConnect: reused pconn FD %d\n", icap->icap_fd);
3313
+	fd_note(icap->icap_fd, icap->current_service->uri);
3314
+	comm_add_close_handler(icap->icap_fd, icapStateFree, icap);
3315
+	theCallback(icap->icap_fd, 0, icap);
3316
+	return 1;
3317
+    }
3318
+    icap->icap_fd = comm_open(SOCK_STREAM, 0, getOutgoingAddr(NULL), 0,
3319
+	COMM_NONBLOCKING, icap->current_service->uri);
3320
+    debug(81, 5) ("icapConnect: new socket, FD %d, local address %s\n",
3321
+	icap->icap_fd, inet_ntoa(getOutgoingAddr(NULL)));
3322
+    if (icap->icap_fd < 0) {
3323
+	icapStateFree(-1, icap);	/* XXX test */
3324
+	return 0;
3325
+    }
3326
+    icap->flags.connect_pending = 1;
3327
+    /*
3328
+     * Configure timeout and close handler before calling
3329
+     * connect because commConnectStart() might get an error
3330
+     * immediately and close the descriptor before it returns.
3331
+     */
3332
+    commSetTimeout(icap->icap_fd, Config.Timeout.connect,
3333
+	icapConnectTimeout, icap);
3334
+    comm_add_close_handler(icap->icap_fd, icapStateFree, icap);
3335
+    /*
3336
+     * This sucks.  commConnectStart() may fail before returning,
3337
+     * so lets lock the data and check its validity afterwards.
3338
+     */
3339
+    cbdataLock(icap);
3340
+    commConnectStart(icap->icap_fd,
3341
+	icap->current_service->hostname,
3342
+	icap->current_service->port, theCallback, icap);
3343
+    rc = cbdataValid(icap);
3344
+    cbdataUnlock(icap);
3345
+    debug(81, 3) ("icapConnect: returning %d\n", rc);
3346
+    return rc;
3347
+}
3348
+
3349
+IcapStateData *
3350
+icapAllocate(void)
3351
+{
3352
+    IcapStateData *icap;
3353
+
3354
+    if (!Config.icapcfg.onoff)
3355
+	return 0;
3356
+
3357
+    icap = cbdataAlloc(IcapStateData);
3358
+    icap->icap_fd = -1;
3359
+    icap->enc.res_hdr = -1;
3360
+    icap->enc.res_body = -1;
3361
+    icap->enc.req_hdr = -1;
3362
+    icap->enc.req_body = -1;
3363
+    icap->enc.opt_body = -1;
3364
+    icap->enc.null_body = -1;
3365
+    icap->chunk_size = -1;
3366
+    memBufDefInit(&icap->icap_hdr);
3367
+
3368
+    debug(81, 3) ("New ICAP state\n");
3369
+    return icap;
3370
+}
3371
+
3372
+void
3373
+icapStateFree(int fd, void *data)
3374
+{
3375
+    IcapStateData *icap = data;
3376
+    debug(81, 3) ("icapStateFree: FD %d, icap %p\n", fd, icap);
3377
+    assert(icap);
3378
+    assert(-1 == fd || fd == icap->icap_fd);
3379
+    if (icap->respmod.entry) {
3380
+	/*
3381
+	 * If we got some error on this side (like ECONNRESET)
3382
+	 * we must signal the other side(s) with a storeAbort()
3383
+	 * call.
3384
+	 */
3385
+	if (icap->respmod.entry->store_status != STORE_OK)
3386
+	    storeAbort(icap->respmod.entry);
3387
+	storeUnlockObject(icap->respmod.entry);
3388
+	icap->respmod.entry = NULL;
3389
+    }
3390
+    requestUnlink(icap->request);
3391
+    icap->request = NULL;
3392
+    if (!memBufIsNull(&icap->icap_hdr))
3393
+	memBufClean(&icap->icap_hdr);
3394
+    if (!memBufIsNull(&icap->respmod.buffer))
3395
+	memBufClean(&icap->respmod.buffer);
3396
+    if (!memBufIsNull(&icap->respmod.req_hdr_copy))
3397
+	memBufClean(&icap->respmod.req_hdr_copy);
3398
+    if (!memBufIsNull(&icap->respmod.resp_copy))
3399
+	memBufClean(&icap->respmod.resp_copy);
3400
+    if (!memBufIsNull(&icap->reqmod.hdr_buf))
3401
+	memBufClean(&icap->reqmod.hdr_buf);
3402
+    if (!memBufIsNull(&icap->reqmod.http_entity.buf))
3403
+	memBufClean(&icap->reqmod.http_entity.buf);
3404
+    if (!memBufIsNull(&icap->chunk_buf))
3405
+	memBufClean(&icap->chunk_buf);
3406
+    if (icap->httpState)
3407
+	httpStateFree(-1, icap->httpState);
3408
+    cbdataUnlock(icap->reqmod.client_cookie);
3409
+    cbdataFree(icap);
3410
+}
3411
+
3412
+void
3413
+icapConnectTimeout(int fd, void *data)
3414
+{
3415
+    IcapStateData *icap = data;
3416
+    debug(81, 3) ("icapConnectTimeout: FD %d, unreachable=1\n", fd);
3417
+    assert(fd == icap->icap_fd);
3418
+    icapOptSetUnreachable(icap->current_service);
3419
+    comm_close(fd);
3420
+}
3421
+
3422
+void
3423
+icapReadTimeout(int fd, void *data)
3424
+{
3425
+    IcapStateData *icap = data;
3426
+    assert(fd == icap->icap_fd);
3427
+    if (icap->flags.wait_for_preview_reply || icap->flags.http_server_eof) {
3428
+	debug(81, 3) ("icapReadTimeout: FD %d, unreachable=1\n", fd);
3429
+	icapOptSetUnreachable(icap->current_service);
3430
+    } else
3431
+	debug(81, 3) ("icapReadTimeout: FD %d, still reachable\n", fd);
3432
+    comm_close(fd);
3433
+}
3434
+
3435
+icap_service_t
3436
+icapServiceToType(const char *s)
3437
+{
3438
+    if (!strcmp(s, "reqmod_precache"))
3439
+	return ICAP_SERVICE_REQMOD_PRECACHE;
3440
+    if (!strcmp(s, "reqmod_postcache"))
3441
+	return ICAP_SERVICE_REQMOD_POSTCACHE;
3442
+    if (!strcmp(s, "respmod_precache"))
3443
+	return ICAP_SERVICE_RESPMOD_PRECACHE;
3444
+    if (!strcmp(s, "respmod_postcache"))
3445
+	return ICAP_SERVICE_RESPMOD_POSTCACHE;
3446
+    return ICAP_SERVICE_MAX;
3447
+}
3448
+
3449
+const char *
3450
+icapServiceToStr(const icap_service_t type)
3451
+{
3452
+    if (type >= 0 && type < ICAP_SERVICE_MAX)
3453
+	return icap_service_type_str[type];
3454
+    else
3455
+	return "error";
3456
+}
3457
+
3458
+
3459
+/* copied from clientAclChecklistCreate */
3460
+static aclCheck_t *
3461
+icapAclChecklistCreate(const acl_access * acl, const clientHttpRequest * http)
3462
+{
3463
+    aclCheck_t *ch;
3464
+    ConnStateData *conn = http->conn;
3465
+    ch = aclChecklistCreate(acl, http->request, 0);
3466
+    ch->conn = conn;
3467
+    cbdataLock(ch->conn);
3468
+    return ch;
3469
+}
3470
+
3471
+/*
3472
+ * check wether we do icap for a request
3473
+ */
3474
+int
3475
+icapCheckAcl(clientHttpRequest * http)
3476
+{
3477
+    icap_access *iter;
3478
+    aclCheck_t *icapChecklist;
3479
+
3480
+    for (iter = Config.icapcfg.access_head; iter; iter = iter->next) {
3481
+	acl_access *A = iter->access;
3482
+	icapChecklist = icapAclChecklistCreate(A, http);
3483
+	if (aclMatchAclList(A->acl_list, icapChecklist)) {
3484
+	    debug(81, 5) ("icapCheckAcl: match for class=%s\n",
3485
+		iter->class->name);
3486
+	    if (A->allow) {
3487
+		/* allow rule, do icap and use associated class */
3488
+		http->request->class = iter->class;
3489
+		aclChecklistFree(icapChecklist);
3490
+		return 1;
3491
+	    } else {
3492
+		/* deny rule, stop processing */
3493
+		aclChecklistFree(icapChecklist);
3494
+		return 0;
3495
+	    }
3496
+	}
3497
+	aclChecklistFree(icapChecklist);
3498
+    }
3499
+    return 0;
3500
+}
3501
+
3502
+/* icapLineLength
3503
+ *
3504
+ * returns the amount of data until lineending ( \r\n )
3505
+ * This function is NOT tolerant of variations of \r\n.
3506
+ */
3507
+size_t
3508
+icapLineLength(const char *start, int len)
3509
+{
3510
+    size_t lineLen = 0;
3511
+    char *end = (char *) memchr(start, '\r', len);
3512
+    if (NULL == end)
3513
+	return 0;
3514
+    end++;			/* advance to where '\n' should be */
3515
+    lineLen = end - start + 1;
3516
+    if (lineLen > len) {
3517
+	debug(0, 0) ("icapLineLength: warning lineLen (%d) > len (%d)\n",
3518
+	    lineLen, len);
3519
+	return 0;
3520
+    }
3521
+    if (*end != '\n') {
3522
+	debug(0, 0) ("icapLineLength: warning *end (%x) != '\\n'\n", *end);
3523
+	return 0;
3524
+    }
3525
+    debug(81, 7) ("icapLineLength: returning %d\n", lineLen);
3526
+    return lineLen;
3527
+}
3528
+
3529
+/*
3530
+ * return:
3531
+ *   -1 if EOF before getting end of ICAP header
3532
+ *    0 if we don't have the entire ICAP header yet
3533
+ *    1 if we got the whole header
3534
+ */
3535
+int
3536
+icapReadHeader(int fd, IcapStateData * icap, int *isIcap)
3537
+{
3538
+    int headlen = 0;
3539
+    int len = 0;
3540
+    int peek_sz = EXPECTED_ICAP_HEADER_LEN;
3541
+    int read_sz = 0;
3542
+    LOCAL_ARRAY(char, tmpbuf, SQUID_TCP_SO_RCVBUF);
3543
+    for (;;) {
3544
+	len = recv(fd, tmpbuf, peek_sz, MSG_PEEK);
3545
+	debug(81, 5) ("recv(FD %d, ..., MSG_PEEK) ret %d\n", fd, len);
3546
+	if (len < 0) {
3547
+	    debug(81, 1) ("icapReadHeader: FD %d recv error: %s\n", fd,
3548
+		xstrerror());
3549
+	    return -1;
3550
+	}
3551
+	if (len == 0) {
3552
+	    debug(81, 2) ("icapReadHeader: FD %d recv EOF\n", fd);
3553
+	    return -1;
3554
+	}
3555
+	headlen = headersEnd(tmpbuf, len);
3556
+	debug(81, 3) ("headlen=%d\n", headlen);
3557
+	/*
3558
+	 * break if we now know where the ICAP headers end
3559
+	 */
3560
+	if (headlen)
3561
+	    break;
3562
+	/*
3563
+	 * break if we know there is no more data to read
3564
+	 */
3565
+	if (len < peek_sz)
3566
+	    break;
3567
+	/*
3568
+	 * The ICAP header is larger than (or equal to) our read
3569
+	 * buffer, so double it and try to peek again.
3570
+	 */
3571
+	peek_sz *= 2;
3572
+	if (peek_sz >= SQUID_TCP_SO_RCVBUF) {
3573
+	    debug(81,
3574
+		1) ("icapReadHeader: Failed to find end of ICAP header\n");
3575
+	    debug(81, 1) ("\twithin first %d bytes of response\n",
3576
+		SQUID_TCP_SO_RCVBUF);
3577
+	    debug(81, 1) ("\tpossible persistent connection bug/confusion\n");
3578
+	    return -1;
3579
+	}
3580
+    }
3581
+    /*
3582
+     * Now actually read the data from the kernel
3583
+     */
3584
+    if (headlen)
3585
+	read_sz = headlen;
3586
+    else
3587
+	read_sz = len;
3588
+    len = FD_READ_METHOD(fd, tmpbuf, read_sz);
3589
+    assert(len == read_sz);
3590
+    fd_bytes(fd, len, FD_READ);
3591
+    memBufAppend(&icap->icap_hdr, tmpbuf, len);
3592
+    if (headlen) {
3593
+	/* End of ICAP header found */
3594
+	if (icap->icap_hdr.size < 4)
3595
+	    *isIcap = 0;
3596
+	else if (0 == strncmp(icap->icap_hdr.buf, "ICAP", 4))
3597
+	    *isIcap = 1;
3598
+	else
3599
+	    *isIcap = 0;
3600
+	return 1;
3601
+    }
3602
+    /*
3603
+     * We don't have all the headers yet
3604
+     */
3605
+    return 0;
3606
+}
3607
+
3608
+static int
3609
+icapParseConnectionClose(const IcapStateData * icap, const char *s,
3610
+    const char *e)
3611
+{
3612
+    char *t;
3613
+    char *q;
3614
+    /*
3615
+     * s points to the start of the line "Connection: ... "
3616
+     * e points to *after* the last character on the line
3617
+     */
3618
+    s += 11;			/* skip past Connection: */
3619
+    while (s < e && isspace(*s))
3620
+	s++;
3621
+    if (e - s < 5)
3622
+	return 0;
3623
+    /*
3624
+     * create a buffer that we can use strtok on
3625
+     */
3626
+    t = xmalloc(e - s + 1);
3627
+    strncpy(t, s, e - s);
3628
+    *(t + (e - s)) = '\0';
3629
+    for (q = strtok(t, ","); q; q = strtok(NULL, ",")) {
3630
+	if (0 == strcasecmp(q, "close")) {
3631
+	    xfree(t);
3632
+	    return 1;
3633
+	}
3634
+    }
3635
+    xfree(t);
3636
+    return 0;
3637
+}
3638
+
3639
+/* returns icap status, version and subversion extracted from status line or -1 on parsing failure 
3640
+ * The str_status pointr points to the text returned from the icap server.
3641
+ * sline probably is NOT terminated with '\0' 
3642
+ */
3643
+int
3644
+icapParseStatusLine(const char *sline, int slinesize, int *version_major,
3645
+    int *version_minor, const char **str_status)
3646
+{
3647
+    char *sp, *stmp, *ep = (char *) sline + slinesize;
3648
+    int status;
3649
+    if (slinesize < 14)		/*The format of this line is: "ICAP/x.x xxx[ msg....]\r\n" */
3650
+	return -1;
3651
+
3652
+    if (strncmp(sline, "ICAP/", 5) != 0)
3653
+	return -1;
3654
+    if (sscanf(sline + 5, "%d.%d", version_major, version_minor) != 2)
3655
+	return -1;
3656
+
3657
+    if (!(sp = memchr(sline, ' ', slinesize)))
3658
+	return -1;
3659
+
3660
+    while (sp < ep && xisspace(*++sp));
3661
+
3662
+    if (!xisdigit(*sp) || sp >= ep)
3663
+	return -1;
3664
+
3665
+    if ((status = strtol(sp, &stmp, 10)) <= 0)
3666
+	return -1;
3667
+    sp = stmp;
3668
+
3669
+    while (sp < ep && xisspace(*++sp));
3670
+    *str_status = sp;
3671
+    /*Must add a test for "\r\n" end headers .... */
3672
+    return status;
3673
+}
3674
+
3675
+
3676
+void
3677
+icapSetKeepAlive(IcapStateData * icap, const char *hdrs)
3678
+{
3679
+    const char *start;
3680
+    const char *end;
3681
+    if (0 == icap->flags.keep_alive)
3682
+	return;
3683
+    if (0 == icapFindHeader(hdrs, "Connection:", &start, &end)) {
3684
+	icap->flags.keep_alive = 1;
3685
+	return;
3686
+    }
3687
+    if (icapParseConnectionClose(icap, start, end))
3688
+	icap->flags.keep_alive = 0;
3689
+    else
3690
+	icap->flags.keep_alive = 1;
3691
+}
3692
+
3693
+/*
3694
+ * icapParseChunkSize
3695
+ *
3696
+ * Returns the offset where the next chunk starts
3697
+ * return parameter chunk_size;
3698
+ */
3699
+static int
3700
+icapParseChunkSize(const char *buf, int len, int *chunk_size)
3701
+{
3702
+    int chunkSize = 0;
3703
+    char c;
3704
+    size_t start;
3705
+    size_t end;
3706
+    size_t nextStart = 0;
3707
+    debug(81, 3) ("icapParseChunkSize: buf=%p, len=%d\n", buf, len);
3708
+    do {
3709
+	start = nextStart;
3710
+	debug(81, 3) ("icapParseChunkSize: start=%d\n", start);
3711
+	if (len <= start) {
3712
+	    /*
3713
+	     * end of buffer, so far no lines or only empty lines,
3714
+	     * wait for more data. read chunk size with next buffer.
3715
+	     */
3716
+	    *chunk_size = 0;
3717
+	    return 0;
3718
+	}
3719
+	end = start + icapLineLength(buf + start, len - start);
3720
+	nextStart = end;
3721
+	if (end <= start) {
3722
+	    /*
3723
+	     * no line found, need more code here, now we are in
3724
+	     * deep trouble, buffer stops with half a chunk size
3725
+	     * line. For now stop here.
3726
+	     */
3727
+	    debug(81, 1) ("icapParseChunkSize: WARNING in mid-line, ret 0\n");
3728
+	    *chunk_size = 0;
3729
+	    return 0;
3730
+	}
3731
+	while (start < end) {
3732
+	    if (NULL == strchr(w_space, buf[start]))
3733
+		break;
3734
+	    start++;
3735
+	}
3736
+	while (start < end) {
3737
+	    if (NULL == strchr(w_space, buf[end - 1]))
3738
+		break;
3739
+	    end--;
3740
+	}
3741
+	/*
3742
+	 * if now end <= start we got an empty line. The previous
3743
+	 * chunk data should stop with a CRLF. In case that the
3744
+	 * other end does not follow the specs and sends no CRLF
3745
+	 * or too many empty lines, just continue till we have a
3746
+	 * non-empty line.
3747
+	 */
3748
+    } while (end <= start);
3749
+    debug(81, 3) ("icapParseChunkSize: start=%d, end=%d\n", start, end);
3750
+
3751
+    /* Non-empty line: Parse the chunk size */
3752
+    while (start < end) {
3753
+	c = buf[start++];
3754
+	if (c >= 'a' && c <= 'f') {
3755
+	    chunkSize = chunkSize * 16 + c - 'a' + 10;
3756
+	} else if (c >= 'A' && c <= 'F') {
3757
+	    chunkSize = chunkSize * 16 + c - 'A' + 10;
3758
+	} else if (c >= '0' && c <= '9') {
3759
+	    chunkSize = chunkSize * 16 + c - '0';
3760
+	} else {
3761
+	    if (!(c == ';' || c == ' ' || c == '\t')) {
3762
+		/*Syntax error: Chunksize expected. */
3763
+		*chunk_size = -2;	/* we are done */
3764
+		return nextStart;
3765
+	    }
3766
+	    /* Next comes a chunk extension */
3767
+	    break;
3768
+	}
3769
+    }
3770
+    /*
3771
+     * if we read a zero chunk, we reached the end. Mark this for
3772
+     * icapPconnTransferDone
3773
+     */
3774
+    *chunk_size = (chunkSize > 0) ? chunkSize : -2;
3775
+    debug(81, 3) ("icapParseChunkSize: return nextStart=%d\n", nextStart);
3776
+    return nextStart;
3777
+}
3778
+
3779
+/*
3780
+ * icapParseChunkedBody
3781
+ *
3782
+ * De-chunk an HTTP entity received from the ICAP server.
3783
+ * The 'store' function pointer is storeAppend() or memBufAppend().
3784
+ */
3785
+size_t
3786
+icapParseChunkedBody(IcapStateData * icap, STRCB * store, void *store_data)
3787
+{
3788
+    int bufOffset = 0;
3789
+    size_t bw = 0;
3790
+    MemBuf *cb = &icap->chunk_buf;
3791
+    const char *buf = cb->buf;
3792
+    int len = cb->size;
3793
+
3794
+    if (icap->chunk_size == -2) {
3795
+	debug(81, 3) ("zero end chunk reached\n");
3796
+	return 0;
3797
+    }
3798
+    debug(81, 3) ("%s:%d: chunk_size=%d\n", __FILE__, __LINE__,
3799
+	icap->chunk_size);
3800
+    if (icap->chunk_size < 0) {
3801
+	store(store_data, buf, len);
3802
+	cb->size = 0;
3803
+	return (size_t) len;
3804
+    }
3805
+    debug(81, 3) ("%s:%d: bufOffset=%d, len=%d\n", __FILE__, __LINE__,
3806
+	bufOffset, len);
3807
+    while (bufOffset < len) {
3808
+	debug(81, 3) ("%s:%d: bufOffset=%d, len=%d\n", __FILE__, __LINE__,
3809
+	    bufOffset, len);
3810
+	if (icap->chunk_size == 0) {
3811
+	    int x;
3812
+	    x = icapParseChunkSize(buf + bufOffset,
3813
+		len - bufOffset, &icap->chunk_size);
3814
+	    if (x < 1) {
3815
+		/* didn't find a valid chunk spec */
3816
+		break;
3817
+	    }
3818
+	    bufOffset += x;
3819
+	    debug(81, 3) ("got chunksize %d, new offset %d\n",
3820
+		icap->chunk_size, bufOffset);
3821
+	    if (icap->chunk_size == -2) {
3822
+		debug(81, 3) ("zero end chunk reached\n");
3823
+		break;
3824
+	    }
3825
+	}
3826
+	debug(81, 3) ("%s:%d: X\n", __FILE__, __LINE__);
3827
+	if (icap->chunk_size > 0) {
3828
+	    if (icap->chunk_size >= len - bufOffset) {
3829
+		store(store_data, buf + bufOffset, len - bufOffset);
3830
+		bw += (len - bufOffset);
3831
+		icap->chunk_size -= (len - bufOffset);
3832
+		bufOffset = len;
3833
+	    } else {
3834
+		store(store_data, buf + bufOffset, icap->chunk_size);
3835
+		bufOffset += icap->chunk_size;
3836
+		bw += icap->chunk_size;
3837
+		icap->chunk_size = 0;
3838
+	    }
3839
+	}
3840
+    }
3841
+    if (0 == bufOffset) {
3842
+	(void) 0;
3843
+    } else if (bufOffset == cb->size) {
3844
+	cb->size = 0;
3845
+    } else {
3846
+	assert(bufOffset <= cb->size);
3847
+	xmemmove(cb->buf, cb->buf + bufOffset, cb->size - bufOffset);
3848
+	cb->size -= bufOffset;
3849
+    }
3850
+    return bw;
3851
+}
3852
+
3853
+/*
3854
+ *  icapAddAuthUserHeader
3855
+ *
3856
+ *  Builds and adds the X-Authenticated-User header to an ICAP request headers.
3857
+ */
3858
+void
3859
+icapAddAuthUserHeader(MemBuf * mb, auth_user_request_t * auth_user_request)
3860
+{
3861
+    char *user = authenticateUserRequestUsername(auth_user_request);
3862
+    char *authuser;
3863
+    size_t len, userlen, schemelen, userofslen;
3864
+    char *userofs;
3865
+
3866
+    if (user == NULL) {
3867
+	debug(81, 5) ("icapAddAuthUserHeader: NULL username\n");
3868
+	return;
3869
+    }
3870
+    userlen = strlen(user);
3871
+    schemelen = strlen(Config.icapcfg.auth_scheme);
3872
+    len = userlen + schemelen + 1;
3873
+    authuser = xcalloc(len, 1);
3874
+
3875
+    if ((userofs = strstr(Config.icapcfg.auth_scheme, "%u")) == NULL) {
3876
+	/* simply add user at end of string */
3877
+	snprintf(authuser, len, "%s%s", Config.icapcfg.auth_scheme, user);
3878
+    } else {
3879
+	userofslen = userofs - Config.icapcfg.auth_scheme;
3880
+	xmemcpy(authuser, Config.icapcfg.auth_scheme, userofslen);
3881
+	xmemcpy(authuser + userofslen, user, userlen);
3882
+	xmemcpy(authuser + userofslen + userlen,
3883
+	    userofs + 2, schemelen - (userofslen + 2) + 1);
3884
+    }
3885
+
3886
+    memBufPrintf(mb, "X-Authenticated-User: %s\r\n", base64_encode(authuser));
3887
+    xfree(authuser);
3888
+}
3889
+
3890
+/*
3891
+ *  icapAddOriginIP
3892
+ *
3893
+ *  Builds and adds the X-Server-IP header to an ICAP request headers.
3894
+ */
3895
+void
3896
+icapAddOriginIP(MemBuf *mb, const char *host)
3897
+{
3898
+  const ipcache_addrs *addrs;
3899
+  struct in_addr s;
3900
+
3901
+  if (host == NULL) {
3902
+    debug(81, 5)("icapAddOriginIP: NULL host\n");
3903
+    return;
3904
+  }
3905
+    
3906
+  addrs = ipcache_gethostbyname(host, IP_LOOKUP_IF_MISS);
3907
+  if (addrs == NULL) {
3908
+    /*
3909
+     * http://www.i-cap.org/spec/draft-stecher-icap-subid-00.txt :
3910
+     *
3911
+     * [...] If the meta information for some header is not available,
3912
+     * the header field MUST be omitted.
3913
+     */
3914
+    debug(81, 5)("icapAddOriginIP: can't tell IP address\n");
3915
+    return;
3916
+  }
3917
+
3918
+  s = addrs->in_addrs[0];
3919
+  memBufPrintf(mb, "X-Server-IP: %s\r\n", inet_ntoa(s));
3920
+}
3921
Index: src/icap_opt.c
3922
===================================================================
3923
RCS file: src/icap_opt.c
3924
diff -N src/icap_opt.c
3925
--- /dev/null	1 Jan 1970 00:00:00 -0000
3926
+++ src/icap_opt.c	16 Feb 2006 17:21:45 -0000	1.1.2.18
3927
@@ -0,0 +1,523 @@
3928
+
3929
+/*
3930
+ * $Id$
3931
+ * 
3932
+ * DEBUG: section 81    Internet Content Adaptation Protocol (ICAP) Client OPTIONS
3933
+ * AUTHOR: Ralf Horstmann
3934
+ *
3935
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
3936
+ * ----------------------------------------------------------
3937
+ *
3938
+ *  Squid is the result of efforts by numerous individuals from
3939
+ *  the Internet community; see the CONTRIBUTORS file for full
3940
+ *  details.   Many organizations have provided support for Squid's
3941
+ *  development; see the SPONSORS file for full details.  Squid is
3942
+ *  Copyrighted (C) 2001 by the Regents of the University of
3943
+ *  California; see the COPYRIGHT file for full details.  Squid
3944
+ *  incorporates software developed and/or copyrighted by other
3945
+ *  sources; see the CREDITS file for full details.
3946
+ *
3947
+ *  This program is free software; you can redistribute it and/or modify
3948
+ *  it under the terms of the GNU General Public License as published by
3949
+ *  the Free Software Foundation; either version 2 of the License, or
3950
+ *  (at your option) any later version.
3951
+ *  
3952
+ *  This program is distributed in the hope that it will be useful,
3953
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
3954
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
3955
+ *  GNU General Public License for more details.
3956
+ *  
3957
+ *  You should have received a copy of the GNU General Public License
3958
+ *  along with this program; if not, write to the Free Software
3959
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
3960
+ *
3961
+ */
3962
+
3963
+#include "squid.h"
3964
+
3965
+/*************************************************************/
3966
+
3967
+/*
3968
+ * network related functions for OPTIONS request
3969
+ */
3970
+static void icapOptStart(void *data);
3971
+static void icapOptTimeout(int fd, void *data);
3972
+static void icapOptConnectDone(int server_fd, int status, void *data);
3973
+static void icapOptWriteComplete(int fd, char *bufnotused, size_t size, int errflag, void *data);
3974
+static void icapOptReadReply(int fd, void *data);
3975
+
3976
+/*
3977
+ * reply parsing functions
3978
+ */
3979
+static int icapOptParseReply(icap_service * s, IcapOptData * i);
3980
+static void icapOptParseEntry(icap_service * s, const char *blk_start, const char *blk_end);
3981
+static int icapIsolateLine(const char **parse_start, const char **blk_start, const char **blk_end);
3982
+
3983
+/*
3984
+ * helper functions
3985
+ */
3986
+static void icapOptDataInit(IcapOptData * i);
3987
+static void icapOptDataFree(IcapOptData * i);
3988
+
3989
+/*************************************************************/
3990
+
3991
+#define TIMEOUT 10
3992
+
3993
+void
3994
+icapOptInit()
3995
+{
3996
+    icap_service *s;
3997
+
3998
+    /* iterate over configured services */
3999
+    s = Config.icapcfg.service_head;
4000
+    while (s) {
4001
+	eventAdd("icapOptStart", icapOptStart, s, 5.0, 1);
4002
+	s = s->next;
4003
+    }
4004
+}
4005
+
4006
+void
4007
+icapOptShutdown()
4008
+{
4009
+    icap_service *s;
4010
+
4011
+    s = Config.icapcfg.service_head;
4012
+    while (s) {
4013
+	if (eventFind(icapOptStart, s)) {
4014
+	    eventDelete(icapOptStart, s);
4015
+	}
4016
+	s = s->next;
4017
+    }
4018
+}
4019
+
4020
+/*
4021
+ * mark a service as unreachable
4022
+ */
4023
+void
4024
+icapOptSetUnreachable(icap_service * s)
4025
+{
4026
+    s->unreachable = 1;
4027
+    debug(81, 5) ("icapOptSetUnreachable: got called for %s\n", s->uri);
4028
+    /*
4029
+     * if there is an options request scheduled, delete it and add
4030
+     * it again to reset the time to the default check_interval.
4031
+     */
4032
+    if (eventFind(icapOptStart, s)) {
4033
+	eventDelete(icapOptStart, s);
4034
+	eventAdd("icapOptStart", icapOptStart, s, Config.icapcfg.check_interval, 1);
4035
+    }
4036
+}
4037
+
4038
+static void
4039
+icapOptStart(void *data)
4040
+{
4041
+    icap_service *s = data;
4042
+    int fd;
4043
+    int ctimeout = TIMEOUT;
4044
+    const char *host = s->hostname;
4045
+    unsigned short port = s->port;
4046
+    debug(81, 3) ("icapOptStart: starting OPTIONS request for %s (%s)\n", s->name, s->uri);
4047
+    fd = comm_open(SOCK_STREAM,
4048
+	0,
4049
+	getOutgoingAddr(NULL),
4050
+	0,
4051
+	COMM_NONBLOCKING,
4052
+	"ICAP OPTIONS connection");
4053
+    if (fd < 0) {
4054
+	debug(81, 4) ("icapConnectStart: %s\n", xstrerror());
4055
+	eventAdd("icapOptStart", icapOptStart, s, Config.icapcfg.check_interval, 1);
4056
+	return;
4057
+    }
4058
+    assert(s->opt == NULL);	/* if not null, another options request might be running, which should not happen */
4059
+    s->opt = memAllocate(MEM_ICAP_OPT_DATA);
4060
+    icapOptDataInit(s->opt);
4061
+    cbdataLock(s);
4062
+    commSetTimeout(fd, ctimeout, icapOptTimeout, s);
4063
+    commConnectStart(fd, host, port, icapOptConnectDone, s);
4064
+}
4065
+
4066
+static void
4067
+icapOptTimeout(int fd, void *data)
4068
+{
4069
+    icap_service *s = data;
4070
+    IcapOptData *i = s->opt;
4071
+    int valid;
4072
+
4073
+    debug(81, 4) ("icapOptConnectTimeout: fd=%d, service=%s\n", fd, s->uri);
4074
+
4075
+    comm_close(fd);
4076
+    valid = cbdataValid(s);
4077
+    cbdataUnlock(s);
4078
+    if (!valid) {
4079
+	icapOptDataFree(i);
4080
+	s->opt = NULL;
4081
+	return;
4082
+    }
4083
+    /* try again later */
4084
+    icapOptDataFree(i);
4085
+    s->opt = NULL;
4086
+    s->unreachable = 1;
4087
+    debug(81, 3) ("icapOptConnectTimeout: unreachable=1, service=%s\n", s->uri);
4088
+    eventAdd("icapOptStart", icapOptStart, s, Config.icapcfg.check_interval, 1);
4089
+
4090
+}
4091
+
4092
+static void
4093
+icapOptConnectDone(int server_fd, int status, void *data)
4094
+{
4095
+    icap_service *s = data;
4096
+    IcapOptData *i = s->opt;
4097
+    MemBuf request;
4098
+    int valid;
4099
+
4100
+    valid = cbdataValid(s);
4101
+    cbdataUnlock(s);
4102
+    if (!valid) {
4103
+	comm_close(server_fd);
4104
+	icapOptDataFree(i);
4105
+	s->opt = NULL;
4106
+	return;
4107
+    }
4108
+    if (status != COMM_OK) {
4109
+	debug(81, 3) ("icapOptConnectDone: unreachable=1, service=%s\n", s->uri);
4110
+	comm_close(server_fd);
4111
+	icapOptDataFree(i);
4112
+	s->opt = NULL;
4113
+	s->unreachable = 1;
4114
+	eventAdd("icapOptStart", icapOptStart, s, Config.icapcfg.check_interval, 1);
4115
+	return;
4116
+    }
4117
+    debug(81, 3) ("icapOptConnectDone: Connection ok. Sending Options request for %s\n", s->name);
4118
+    memBufDefInit(&request);
4119
+    memBufPrintf(&request, "OPTIONS %s ICAP/1.0\r\n", s->uri);
4120
+    memBufPrintf(&request, "Host: %s\r\n", s->hostname);
4121
+    memBufPrintf(&request, "Connection: close\r\n");
4122
+    memBufPrintf(&request, "User-Agent: ICAP-Client-Squid/1.2\r\n");
4123
+    memBufPrintf(&request, "\r\n");
4124
+    cbdataLock(s);
4125
+    commSetTimeout(server_fd, TIMEOUT, icapOptTimeout, s);
4126
+    comm_write_mbuf(server_fd, request, icapOptWriteComplete, s);
4127
+}
4128
+
4129
+static void
4130
+icapOptWriteComplete(int fd, char *bufnotused, size_t size, int errflag, void *data)
4131
+{
4132
+    icap_service *s = data;
4133
+    IcapOptData *i = s->opt;
4134
+    int valid;
4135
+
4136
+    valid = cbdataValid(s);
4137
+    cbdataUnlock(s);
4138
+    if (!valid) {
4139
+	comm_close(fd);
4140
+	icapOptDataFree(i);
4141
+	s->opt = NULL;
4142
+	return;
4143
+    }
4144
+    debug(81, 5) ("icapOptWriteComplete: FD %d: size %d: errflag %d.\n",
4145
+	fd, size, errflag);
4146
+    if (size > 0) {
4147
+	fd_bytes(fd, size, FD_WRITE);
4148
+	kb_incr(&statCounter.icap.all.kbytes_out, size);
4149
+    }
4150
+    if (errflag) {
4151
+	/* cancel this for now */
4152
+	debug(81, 3) ("icapOptWriteComplete: unreachable=1, service=%s\n", s->uri);
4153
+	icapOptDataFree(i);
4154
+	s->opt = NULL;
4155
+	s->unreachable = 1;
4156
+	eventAdd("icapOptStart", icapOptStart, s, Config.icapcfg.check_interval, 1);
4157
+	comm_close(fd);
4158
+	return;
4159
+    }
4160
+    cbdataLock(s);
4161
+    commSetSelect(fd, COMM_SELECT_READ, icapOptReadReply, s, 0);
4162
+}
4163
+
4164
+static void
4165
+icapOptReadReply(int fd, void *data)
4166
+{
4167
+    icap_service *s = data;
4168
+    IcapOptData *i = s->opt;
4169
+    int size;
4170
+    int len = i->size - i->offset - 1;
4171
+    int valid;
4172
+
4173
+    valid = cbdataValid(s);
4174
+    cbdataUnlock(s);
4175
+    if (!valid) {
4176
+	comm_close(fd);
4177
+	icapOptDataFree(i);
4178
+	s->opt = NULL;
4179
+	return;
4180
+    }
4181
+    if (len == 0) {
4182
+	/* Grow the request memory area to accomodate for a large request */
4183
+	printf("PANIC: not enough memory\n");
4184
+#if 0
4185
+	i->buf = memReallocBuf(i->buf, i->size * 2, &i->size);
4186
+	debug(81, 2) ("icapoptReadReply: growing reply buffer: offset=%ld size=%ld\n",
4187
+	    (long) i->offset, (long) i->size);
4188
+	len = i->size - i->offset - 1;
4189
+#endif
4190
+    }
4191
+    size = FD_READ_METHOD(fd, i->buf + i->offset, len);
4192
+    i->offset += size;
4193
+    debug(81, 3) ("icapOptReadReply: Got %d bytes of data\n", size);
4194
+    if (size > 0) {
4195
+	/* do some statistics */
4196
+	fd_bytes(fd, size, FD_READ);
4197
+	kb_incr(&statCounter.icap.all.kbytes_in, size);
4198
+
4199
+	/* 
4200
+	 * some icap servers seem to ignore the  "Connection: close" header. so 
4201
+	 * after getting the complete option reply we close the connection 
4202
+	 * ourself.
4203
+	 */
4204
+	if ((i->headlen = headersEnd(i->buf, i->offset))) {
4205
+	    debug(81, 3) ("icapOptReadReply: EndOfResponse\n");
4206
+	    size = 0;
4207
+	}
4208
+    }
4209
+    if (size < 0) {
4210
+	debug(81, 3) ("icapOptReadReply: FD %d: read failure: %s.\n", fd, xstrerror());
4211
+	debug(81, 3) ("icapOptReadReply: unreachable=1, service=%s.\n", s->uri);
4212
+	s->unreachable = 1;
4213
+	icapOptDataFree(i);
4214
+	s->opt = NULL;
4215
+	eventAdd("icapOptStart", icapOptStart, s, Config.icapcfg.check_interval, 1);
4216
+	comm_close(fd);
4217
+    } else if (size == 0) {
4218
+	/* no more data, now we can parse the reply */
4219
+	debug(81, 3) ("icapOptReadReply: FD %d: connection closed\n", fd);
4220
+	i->buf[i->offset] = '\0';	/* for string functions */
4221
+	debug(81, 3) ("icapOptReadReply: unreachable=0, service=%s\n", s->uri);
4222
+
4223
+	if (!icapOptParseReply(s, i)) {
4224
+	    debug(81, 3) ("icapOptReadReply: OPTIONS request not successful. scheduling again in %d seconds\n", Config.icapcfg.check_interval);
4225
+	    s->unreachable = 1;
4226
+	} else
4227
+	    s->unreachable = 0;
4228
+
4229
+	if (s->options_ttl <= 0)
4230
+	    s->options_ttl = Config.icapcfg.check_interval;
4231
+	eventAdd("icapOptStart", icapOptStart, s, s->options_ttl, 1);
4232
+
4233
+	icapOptDataFree(i);
4234
+	s->opt = NULL;
4235
+	comm_close(fd);
4236
+    } else {
4237
+	/* data received */
4238
+	/* commSetSelect(fd, Type, handler, client_data, timeout) */
4239
+	cbdataLock(s);
4240
+	commSetSelect(fd, COMM_SELECT_READ, icapOptReadReply, data, 0);
4241
+    }
4242
+}
4243
+
4244
+static int
4245
+icapIsolateLine(const char **parse_start, const char **blk_start, const char **blk_end)
4246
+{
4247
+    int slen = strcspn(*parse_start, "\r\n");
4248
+
4249
+    if (!(*parse_start)[slen])	/* no crlf */
4250
+	return 0;
4251
+
4252
+    if (slen == 0)		/* empty line */
4253
+	return 0;
4254
+
4255
+    *blk_start = *parse_start;
4256
+    *blk_end = *blk_start + slen;
4257
+
4258
+    /* set it to the beginning of next line */
4259
+    *parse_start = *blk_end;
4260
+    while (**parse_start == '\r')	/* CR */
4261
+	(*parse_start)++;
4262
+    if (**parse_start == '\n')	/* LF */
4263
+	(*parse_start)++;
4264
+    return 1;
4265
+}
4266
+
4267
+/* process a single header entry between blk_start and blk_end */
4268
+static void
4269
+icapOptParseEntry(icap_service * s, const char *blk_start, const char *blk_end)
4270
+{
4271
+    const char *name_end = strchr(blk_start, ':');
4272
+    const int name_len = name_end ? name_end - blk_start : 0;
4273
+    const char *value_start = blk_start + name_len + 1;		/* skip ':' */
4274
+    int value_len;
4275
+    int new;
4276
+
4277
+    if (!name_len || name_end > blk_end) {
4278
+	debug(81, 5) ("icapOptParseEntry: strange header. skipping\n");
4279
+	return;
4280
+    }
4281
+    if (name_len > 65536) {
4282
+	debug(81, 5) ("icapOptParseEntry: unusual long header item. skipping.\n");
4283
+	return;
4284
+    }
4285
+    while (xisspace(*value_start) && value_start < blk_end) {
4286
+	value_start++;
4287
+    }
4288
+    if (value_start >= blk_end) {
4289
+	debug(81, 5) ("icapOptParseEntry: no value found\n");
4290
+	return;
4291
+    }
4292
+    value_len = blk_end - value_start;
4293
+
4294
+
4295
+    /* extract information */
4296
+    if (!strncasecmp("Allow", blk_start, name_len)) {
4297
+	debug(81, 5) ("icapOptParseEntry: found Allow\n");
4298
+	if (!strncmp("204", value_start, 3)) {
4299
+	    s->flags.allow_204 = 1;
4300
+	} else {
4301
+	    debug(81, 3) ("icapOptParseEntry: Allow value unknown");
4302
+	}
4303
+    } else if (!strncasecmp("Connection", blk_start, name_len)) {
4304
+	debug(81, 5) ("icapOptParseEntry: found Connection\n");
4305
+    } else if (!strncasecmp("Encapsulated", blk_start, name_len)) {
4306
+	debug(81, 5) ("icapOptParseEntry: found Encapsulated\n");
4307
+    } else if (!strncasecmp("ISTAG", blk_start, name_len)) {
4308
+	debug(81, 5) ("icapOptParseEntry: found ISTAG\n");
4309
+	stringClean(&s->istag);
4310
+	stringLimitInit(&s->istag, value_start, value_len);
4311
+    } else if (!strncasecmp("Max-Connections", blk_start, name_len)) {
4312
+	debug(81, 5) ("icapOptParseEntry: found Max-Connections\n");
4313
+	errno = 0;
4314
+	new = strtol(value_start, NULL, 10);
4315
+	if (errno) {
4316
+	    debug(81, 5) ("icapOptParseEntry: Max-Connections: could not parse value\n");
4317
+	} else {
4318
+	    debug(81, 5) ("icapOptParseEntry: Max-Connections: new value=%d\n", new);
4319
+	    s->max_connections = new;
4320
+	}
4321
+    } else if (!strncasecmp("Methods", blk_start, name_len)) {
4322
+	debug(81, 5) ("icapOptParseEntry: found Methods\n");
4323
+    } else if (!strncasecmp("Options-TTL", blk_start, name_len)) {
4324
+	debug(81, 5) ("icapOptParseEntry: found Options-TTL\n");
4325
+	errno = 0;
4326
+	new = strtol(value_start, NULL, 10);
4327
+	if (errno) {
4328
+	    debug(81, 5) ("icapOptParseEntry: Options-TTL: could not parse value\n");
4329
+	} else {
4330
+	    debug(81, 5) ("icapOptParseEntry: Options-TTL: new value=%d\n", new);
4331
+	    s->options_ttl = new;
4332
+	}
4333
+    } else if (!strncasecmp("Preview", blk_start, name_len)) {
4334
+	debug(81, 5) ("icapOptParseEntry: found Preview\n");
4335
+	errno = 0;
4336
+	new = strtol(value_start, NULL, 10);
4337
+	if (errno) {
4338
+	    debug(81, 5) ("icapOptParseEntry: Preview: could not parse value\n");
4339
+	} else {
4340
+	    debug(81, 5) ("icapOptParseEntry: Preview: new value=%d\n", new);
4341
+	    s->preview = new;
4342
+	}
4343
+    } else if (!strncasecmp("Service", blk_start, name_len)) {
4344
+	debug(81, 5) ("icapOptParseEntry: found Service\n");
4345
+    } else if (!strncasecmp("Service-ID", blk_start, name_len)) {
4346
+	debug(81, 5) ("icapOptParseEntry: found Service-ID\n");
4347
+    } else if (!strncasecmp("Transfer-Preview", blk_start, name_len)) {
4348
+	debug(81, 5) ("icapOptParseEntry: found Transfer-Preview\n");
4349
+	stringClean(&s->transfer_preview);
4350
+	stringLimitInit(&s->transfer_preview, value_start, value_len);
4351
+    } else if (!strncasecmp("Transfer-Ignore", blk_start, name_len)) {
4352
+	debug(81, 5) ("icapOptParseEntry: found Transfer-Ignore\n");
4353
+	stringClean(&s->transfer_ignore);
4354
+	stringLimitInit(&s->transfer_ignore, value_start, value_len);
4355
+    } else if (!strncasecmp("Transfer-Complete", blk_start, name_len)) {
4356
+	debug(81, 5) ("icapOptParseEntry: found Transfer-Complete\n");
4357
+	stringClean(&s->transfer_complete);
4358
+	stringLimitInit(&s->transfer_complete, value_start, value_len);
4359
+    } else if (!strncasecmp("X-Include", blk_start, name_len)) {
4360
+	debug(81, 5) ("icapOptParseEntry: found X-Include\n");
4361
+	if (strstr(value_start, "X-Client-IP")) {
4362
+	    debug(81, 5) ("icapOptParseEntry: X-Include: found X-Client-IP\n");
4363
+	    s->flags.need_x_client_ip = 1;
4364
+	}
4365
+	if (strstr(value_start, "X-Server-IP")) {
4366
+	    debug(81, 5) ("icapOptParseEntry: X-Include: found X-Server-IP\n");
4367
+	    s->flags.need_x_server_ip = 1;
4368
+	}
4369
+	if (strstr(value_start, "X-Authenticated-User")) {
4370
+	    debug(81, 5) ("icapOptParseEntry: X-Include: found X-Authenticated-User\n");
4371
+	    s->flags.need_x_authenticated_user = 1;
4372
+	}
4373
+    } else {
4374
+	debug(81, 5) ("icapOptParseEntry: unknown options header\n");
4375
+    }
4376
+}
4377
+
4378
+/* parse OPTIONS reply */
4379
+static int
4380
+icapOptParseReply(icap_service * s, IcapOptData * i)
4381
+{
4382
+    int version_major, version_minor;
4383
+    const char *str_status;
4384
+    int status;
4385
+    const char *buf = i->buf;
4386
+    const char *parse_start;
4387
+    const char *head_end;
4388
+    const char *blk_start;
4389
+    const char *blk_end;
4390
+
4391
+    if ((status =
4392
+	    icapParseStatusLine(i->buf, i->offset,
4393
+		&version_major, &version_minor, &str_status)) < 0) {
4394
+	debug(81, 2) ("icapOptParseReply: bad status line <%s>\n", i->buf);
4395
+	return 0;
4396
+    }
4397
+    debug(81, 3) ("icapOptParseReply: got reply: <ICAP/%d.%d %d %s>\n", version_major, version_minor, status, str_status);
4398
+
4399
+    if (status != 200) {
4400
+	debug(81, 3) ("icapOptParseReply: status = %d != 200\n", status);
4401
+	return 0;
4402
+    }
4403
+    parse_start = buf;
4404
+    if (i->headlen == 0)
4405
+	i->headlen = headersEnd(parse_start, s->opt->offset);
4406
+
4407
+    if (!i->headlen) {
4408
+	debug(81, 2) ("icapOptParseReply: end of headers could not be found\n");
4409
+	return 0;
4410
+    }
4411
+    head_end = parse_start + i->headlen - 1;
4412
+    while (*(head_end - 1) == '\r')
4413
+	head_end--;
4414
+    assert(*(head_end - 1) == '\n');
4415
+    if (*head_end != '\r' && *head_end != '\n')
4416
+	return 0;		/* failure */
4417
+
4418
+    /* skip status line */
4419
+    if (!icapIsolateLine(&parse_start, &blk_start, &blk_end)) {
4420
+	debug(81, 3) ("icapOptParseReply: failure in isolating status line\n");
4421
+	return 0;
4422
+
4423
+    }
4424
+    /* now we might start real parsing */
4425
+    while (icapIsolateLine(&parse_start, &blk_start, &blk_end)) {
4426
+	if (blk_end > head_end || blk_start > head_end || blk_start >= blk_end) {
4427
+	    debug(81, 3) ("icapOptParseReply: header limit exceeded. finished.\n");
4428
+	    break;
4429
+	}
4430
+	icapOptParseEntry(s, blk_start, blk_end);
4431
+    }
4432
+    return 1;
4433
+}
4434
+
4435
+static void
4436
+icapOptDataInit(IcapOptData * i)
4437
+{
4438
+    i->buf = memAllocBuf(HTTP_REPLY_BUF_SZ, &i->size);
4439
+    i->offset = 0;
4440
+    i->headlen = 0;
4441
+}
4442
+
4443
+static void
4444
+icapOptDataFree(IcapOptData * i)
4445
+{
4446
+    if (i) {
4447
+	memFreeBuf(i->size, i->buf);
4448
+	memFree(i, MEM_ICAP_OPT_DATA);
4449
+    }
4450
+}
4451
Index: src/icap_reqmod.c
4452
===================================================================
4453
RCS file: src/icap_reqmod.c
4454
diff -N src/icap_reqmod.c
4455
--- /dev/null	1 Jan 1970 00:00:00 -0000
4456
+++ src/icap_reqmod.c	17 Feb 2006 12:50:52 -0000	1.1.2.60
4457
@@ -0,0 +1,981 @@
4458
+
4459
+/*
4460
+ * $Id$
4461
+ *
4462
+ * DEBUG: section 81    Internet Content Adaptation Protocol (ICAP) Client
4463
+ * AUTHOR: Geetha Manjunath, Hewlett Packard Company
4464
+ *
4465
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
4466
+ * ----------------------------------------------------------
4467
+ *
4468
+ *  Squid is the result of efforts by numerous individuals from
4469
+ *  the Internet community; see the CONTRIBUTORS file for full
4470
+ *  details.   Many organizations have provided support for Squid's
4471
+ *  development; see the SPONSORS file for full details.  Squid is
4472
+ *  Copyrighted (C) 2001 by the Regents of the University of
4473
+ *  California; see the COPYRIGHT file for full details.  Squid
4474
+ *  incorporates software developed and/or copyrighted by other
4475
+ *  sources; see the CREDITS file for full details.
4476
+ *
4477
+ *  This program is free software; you can redistribute it and/or modify
4478
+ *  it under the terms of the GNU General Public License as published by
4479
+ *  the Free Software Foundation; either version 2 of the License, or
4480
+ *  (at your option) any later version.
4481
+ *  
4482
+ *  This program is distributed in the hope that it will be useful,
4483
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
4484
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
4485
+ *  GNU General Public License for more details.
4486
+ *  
4487
+ *  You should have received a copy of the GNU General Public License
4488
+ *  along with this program; if not, write to the Free Software
4489
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
4490
+ *
4491
+ */
4492
+
4493
+#include "squid.h"
4494
+
4495
+#define ICAP_PROXY_KEEP_ALIVE 0
4496
+
4497
+/*
4498
+ * These once-static functions are required to be global for ICAP
4499
+ */
4500
+
4501
+PF clientReadRequest;
4502
+PF connStateFree;
4503
+int clientReadDefer(int fd, void *data);
4504
+int clientCheckContentLength(request_t * r);
4505
+void clientProcessRequest(clientHttpRequest *);
4506
+int clientCachable(clientHttpRequest *);
4507
+int clientHierarchical(clientHttpRequest *);
4508
+void clientReadBody(request_t * request, char *buf, size_t size,
4509
+    CBCB * callback, void *cbdata);
4510
+static void icapReqModPassHttpBody(IcapStateData * icap, char *buf, size_t size,
4511
+    CBCB * callback, void *cbdata);
4512
+
4513
+static PF icapReqModReadHttpHdrs;
4514
+static PF icapReqModReadHttpBody;
4515
+static CWCB icapReqModSendBodyChunk;
4516
+static CBCB icapReqModBodyHandler;
4517
+static BODY_HANDLER icapReqModBodyReader;
4518
+static STRCB icapReqModMemBufAppend;
4519
+
4520
+#define EXPECTED_ICAP_HEADER_LEN 256
4521
+static const char *crlf = "\r\n";
4522
+
4523
+/*
4524
+ * icapExpectedHttpReqHdrSize
4525
+ *
4526
+ * calculate the size of the HTTP headers that we expect
4527
+ * to read from the ICAP server.
4528
+ */
4529
+static int
4530
+icapExpectedHttpReqHdrSize(IcapStateData * icap)
4531
+{
4532
+    if (icap->enc.req_body > -1 && icap->enc.req_hdr > -1)
4533
+	return (icap->enc.req_body - icap->enc.req_hdr);
4534
+    if (icap->enc.null_body > -1)
4535
+	return icap->enc.null_body;
4536
+    fatal("icapExpectedHttpReqHdrSize: unexpected case");
4537
+    return 0;
4538
+}
4539
+
4540
+/*
4541
+ * icapReqModCreateClientState
4542
+ *
4543
+ * Creates fake client_side data structures so we can use
4544
+ * that module to read/parse the HTTP request that we read
4545
+ * from the ICAP server.
4546
+ */
4547
+static clientHttpRequest *
4548
+icapReqModCreateClientState(IcapStateData * icap, request_t * request)
4549
+{
4550
+    clientHttpRequest *http;
4551
+    if (!cbdataValid(icap->reqmod.client_cookie)) {
4552
+	debug(81, 3) ("Whups, client cookie invalid\n");
4553
+	icap->reqmod.client_fd = -1;
4554
+	return NULL;
4555
+    }
4556
+    http = cbdataAlloc(clientHttpRequest);
4557
+    /*
4558
+     * use our own urlCanonicalClean here, because urlCanonicalClean
4559
+     * may strip everything after a question-mark. As http->uri
4560
+     * is used when doing a request to a parent proxy, we need the full
4561
+     * url here.
4562
+     */
4563
+    http->uri = xstrdup(urlCanonical(icap->request));
4564
+    http->log_uri = xstrndup(http->uri, MAX_URL);
4565
+    http->range_iter.boundary = StringNull;
4566
+    http->request = requestLink(request ? request : icap->request);
4567
+    http->flags.did_icap_reqmod = 1;
4568
+    http->start = icap->reqmod.start;
4569
+#if ICAP_PROXY_KEEP_ALIVE
4570
+    /*
4571
+     * Here it is possible becouse we are using as client_cookie the original http->conn
4572
+     * if we will keep this code we must declare an icap->conn field........
4573
+     * Will work if pipeline_prefetch is not enabled
4574
+     * We are using a dummy ConnStateData structure, just to free
4575
+     * old clientHttpRequest :-( 
4576
+     * OK,all this code is a hack and possibly must not exists in cvs ......
4577
+     */
4578
+
4579
+    http->conn = icap->reqmod.client_cookie;
4580
+    assert(http->conn->chr->next == NULL);
4581
+    {
4582
+	ConnStateData *dummyconn;
4583
+	dummyconn = cbdataAlloc(ConnStateData);
4584
+	dummyconn->fd = icap->reqmod.client_fd;
4585
+	dummyconn->chr = http->conn->chr;
4586
+	dummyconn->chr->conn = dummyconn;
4587
+	comm_add_close_handler(dummyconn->fd, connStateFree, dummyconn);
4588
+    }
4589
+
4590
+    http->conn->chr = http;
4591
+
4592
+#else
4593
+    http->conn = cbdataAlloc(ConnStateData);
4594
+    http->conn->fd = icap->reqmod.client_fd;
4595
+    http->conn->in.size = 0;
4596
+    http->conn->in.buf = NULL;
4597
+    http->conn->log_addr = icap->reqmod.log_addr;
4598
+    http->conn->chr = http;
4599
+    comm_add_close_handler(http->conn->fd, connStateFree, http->conn);
4600
+#endif
4601
+    http->icap_reqmod = NULL;
4602
+    return http;
4603
+}
4604
+
4605
+/*
4606
+ * icapReqModInterpretHttpRequest
4607
+ *
4608
+ * Interpret an HTTP request that we read from the ICAP server.
4609
+ * Create some "fake" clientHttpRequest and ConnStateData structures
4610
+ * so we can pass this new request off to the routines in
4611
+ * client_side.c.
4612
+ */
4613
+static void
4614
+icapReqModInterpretHttpRequest(IcapStateData * icap, request_t * request)
4615
+{
4616
+    clientHttpRequest *http = icapReqModCreateClientState(icap, request);
4617
+    if (NULL == http)
4618
+	return;
4619
+    /*
4620
+     * bits from clientReadRequest
4621
+     */
4622
+    request->content_length = httpHeaderGetSize(&request->header,
4623
+	HDR_CONTENT_LENGTH);
4624
+    if (!urlCheckRequest(request) ||
4625
+	httpHeaderHas(&request->header, HDR_TRANSFER_ENCODING)) {
4626
+	ErrorState *err;
4627
+	err = errorCon(ERR_UNSUP_REQ, HTTP_NOT_IMPLEMENTED);
4628
+	err->request = requestLink(request);
4629
+	request->flags.proxy_keepalive = 0;
4630
+	http->entry =
4631
+	    clientCreateStoreEntry(http, request->method, null_request_flags);
4632
+	errorAppendEntry(http->entry, err);
4633
+	return;
4634
+    }
4635
+    if (!clientCheckContentLength(request)) {
4636
+	ErrorState *err;
4637
+	err = errorCon(ERR_INVALID_REQ, HTTP_LENGTH_REQUIRED);
4638
+	err->request = requestLink(request);
4639
+	http->entry =
4640
+	    clientCreateStoreEntry(http, request->method, null_request_flags);
4641
+	errorAppendEntry(http->entry, err);
4642
+	return;
4643
+    }
4644
+    /* Do we expect a request-body? */
4645
+    if (request->content_length > 0) {
4646
+	debug(81, 5) ("handing request bodies in ICAP REQMOD\n");
4647
+	if (request->body_reader_data)
4648
+	    cbdataUnlock(request->body_reader_data);
4649
+	request->body_reader = icapReqModBodyReader;
4650
+	request->body_reader_data = icap;	/* XXX cbdataLock? */
4651
+	cbdataLock(icap);	/*Yes sure ..... */
4652
+	memBufDefInit(&icap->reqmod.http_entity.buf);
4653
+    }
4654
+    if (clientCachable(http))
4655
+	request->flags.cachable = 1;
4656
+    if (clientHierarchical(http))
4657
+	request->flags.hierarchical = 1;
4658
+    clientProcessRequest(http);
4659
+}
4660
+
4661
+/*
4662
+ * icapReqModParseHttpError
4663
+ *
4664
+ * Handle an error when parsing the new HTTP request we read
4665
+ * from the ICAP server.
4666
+ */
4667
+static void
4668
+icapReqModParseHttpError(IcapStateData * icap, const char *reason)
4669
+{
4670
+    debug(81, 1) ("icapReqModParseHttpError: %s\n", reason);
4671
+}
4672
+
4673
+/*
4674
+ * icapEntryError
4675
+ *
4676
+ * A wrapper for errorCon() and errorAppendEntry().
4677
+ */
4678
+static void
4679
+icapEntryError(IcapStateData * icap, err_type et, http_status hs, int xerrno)
4680
+{
4681
+    ErrorState *err;
4682
+    clientHttpRequest *http = icapReqModCreateClientState(icap, NULL);
4683
+    if (NULL == http)
4684
+	return;
4685
+    http->entry = clientCreateStoreEntry(http,
4686
+	icap->request->method, null_request_flags);
4687
+    err = errorCon(et, hs);
4688
+    err->xerrno = xerrno;
4689
+    err->request = requestLink(icap->request);
4690
+    errorAppendEntry(http->entry, err);
4691
+}
4692
+
4693
+/*
4694
+ * icapReqModParseHttpRequest
4695
+ * 
4696
+ * Parse the HTTP request that we read from the ICAP server.
4697
+ * Creates and fills in the request_t structure.
4698
+ */
4699
+static void
4700
+icapReqModParseHttpRequest(IcapStateData * icap)
4701
+{
4702
+    char *mstr;
4703
+    char *uri;
4704
+    char *inbuf;
4705
+    char *t;
4706
+    char *token;
4707
+    char *headers;
4708
+    method_t method;
4709
+    request_t *request;
4710
+    http_version_t http_ver;
4711
+    int reqlen = icap->reqmod.hdr_buf.size;
4712
+    int hdrlen;
4713
+
4714
+    /*
4715
+     * Lazy, make a copy of the buf so I can chop it up with strtok()
4716
+     */
4717
+    inbuf = xcalloc(reqlen + 1, 1);
4718
+    memcpy(inbuf, icap->reqmod.hdr_buf.buf, reqlen);
4719
+
4720
+    if ((mstr = strtok(inbuf, "\t ")) == NULL) {
4721
+	debug(81, 1) ("icapReqModParseHttpRequest: Can't get request method\n");
4722
+	icapReqModParseHttpError(icap, "error:invalid-request-method");
4723
+	xfree(inbuf);
4724
+	return;
4725
+    }
4726
+    method = urlParseMethod(mstr);
4727
+    if (method == METHOD_NONE) {
4728
+	debug(81, 1) ("icapReqModParseHttpRequest: Unsupported method '%s'\n",
4729
+	    mstr);
4730
+	icapReqModParseHttpError(icap, "error:unsupported-request-method");
4731
+	xfree(inbuf);
4732
+	return;
4733
+    }
4734
+    /* look for URL+HTTP/x.x */
4735
+    if ((uri = strtok(NULL, "\n")) == NULL) {
4736
+	debug(81, 1) ("icapReqModParseHttpRequest: Missing URI\n");
4737
+	icapReqModParseHttpError(icap, "error:missing-url");
4738
+	xfree(inbuf);
4739
+	return;
4740
+    }
4741
+    while (xisspace(*uri))
4742
+	uri++;
4743
+    t = uri + strlen(uri);
4744
+    assert(*t == '\0');
4745
+    token = NULL;
4746
+    while (t > uri) {
4747
+	t--;
4748
+	if (xisspace(*t) && !strncmp(t + 1, "HTTP/", 5)) {
4749
+	    token = t + 1;
4750
+	    break;
4751
+	}
4752
+    }
4753
+    while (t > uri && xisspace(*t))
4754
+	*(t--) = '\0';
4755
+    debug(81, 5) ("icapReqModParseHttpRequest: URI is '%s'\n", uri);
4756
+    if (token == NULL) {
4757
+	debug(81, 3) ("icapReqModParseHttpRequest: Missing HTTP identifier\n");
4758
+	icapReqModParseHttpError(icap, "error:missing-http-ident");
4759
+	xfree(inbuf);
4760
+	return;
4761
+    }
4762
+    if (sscanf(token + 5, "%d.%d", &http_ver.major, &http_ver.minor) != 2) {
4763
+	debug(81, 3) ("icapReqModParseHttpRequest: Invalid HTTP identifier.\n");
4764
+	icapReqModParseHttpError(icap, "error:invalid-http-ident");
4765
+	xfree(inbuf);
4766
+	return;
4767
+    }
4768
+    debug(81, 6) ("icapReqModParseHttpRequest: Client HTTP version %d.%d.\n",
4769
+	http_ver.major, http_ver.minor);
4770
+
4771
+    headers = strtok(NULL, null_string);
4772
+    hdrlen = inbuf + reqlen - headers;
4773
+
4774
+    if ((request = urlParse(method, uri)) == NULL) {
4775
+	debug(81, 3) ("Invalid URL: %s at %s:%d\n", uri, __FILE__, __LINE__);
4776
+	icapEntryError(icap, ERR_INVALID_URL, HTTP_BAD_REQUEST, 0);
4777
+	xfree(inbuf);
4778
+	return;
4779
+    }
4780
+    /* compile headers */
4781
+    if (!httpHeaderParse(&request->header, headers, headers + hdrlen)) {
4782
+	debug(81, 3) ("Failed to parse HTTP headers for: %s at %s:%d",
4783
+	    uri, __FILE__, __LINE__);
4784
+	icapEntryError(icap, ERR_INVALID_REQ, HTTP_BAD_REQUEST, 0);
4785
+	xfree(inbuf);
4786
+	return;
4787
+    }
4788
+    debug(81,
4789
+	3)
4790
+	("icapReqModParseHttpRequest: successfully parsed the HTTP request\n");
4791
+    request->http_ver = http_ver;
4792
+    request->client_addr = icap->request->client_addr;
4793
+    request->my_addr = icap->request->my_addr;
4794
+    request->my_port = icap->request->my_port;
4795
+    request->class = icap->request->class;
4796
+    if (icap->request->auth_user_request != NULL) {
4797
+	/* Copy authentification info in new request */
4798
+	request->auth_user_request = icap->request->auth_user_request;
4799
+	authenticateAuthUserRequestLock(request->auth_user_request);
4800
+    }
4801
+#if ICAP_PROXY_KEEP_ALIVE
4802
+    /*
4803
+     * Copy the proxy_keepalive flag from the original request
4804
+     */
4805
+    request->flags.proxy_keepalive = icap->request->flags.proxy_keepalive;
4806
+    /*
4807
+     * If proxy_keepalive was set for the original request, make
4808
+     * sure that the adapated request also has the necessary headers
4809
+     * for keepalive
4810
+     */
4811
+    if (request->flags.proxy_keepalive) {
4812
+	if (!httpMsgIsPersistent(http_ver, &request->header))
4813
+	    request->flags.proxy_keepalive = 0;
4814
+    }
4815
+#endif
4816
+    icapReqModInterpretHttpRequest(icap, request);
4817
+    xfree(inbuf);
4818
+}
4819
+
4820
+/*
4821
+ * icapReqModHandoffRespMod
4822
+ *
4823
+ * Handles the case where a REQMOD request results in an HTTP REPLY
4824
+ * (instead of an ICAP REPLY that contains a new HTTP REQUEST).  We
4825
+ * prepare the IcapStateData for passing off to the icap_reqmod
4826
+ * code, where we have functions for reading HTTP replies in ICAP
4827
+ * messages.
4828
+ */
4829
+static void
4830
+icapReqModHandoffRespMod(IcapStateData * icap)
4831
+{
4832
+    extern PF icapReadReply;
4833
+    clientHttpRequest *http = icapReqModCreateClientState(icap, NULL);
4834
+    if (NULL == http)
4835
+	return;
4836
+    assert(icap->request);
4837
+
4838
+    http->entry = clientCreateStoreEntry(http,
4839
+	icap->request->method, icap->request->flags);
4840
+    icap->respmod.entry = http->entry;
4841
+    storeLockObject(icap->respmod.entry);
4842
+
4843
+    /* icap->http_flags = ? */
4844
+    memBufDefInit(&icap->respmod.buffer);
4845
+    memBufDefInit(&icap->chunk_buf);
4846
+    assert(icap->current_service);
4847
+    icapReadReply(icap->icap_fd, icap);
4848
+}
4849
+
4850
+/*
4851
+ * icapReqModKeepAliveOrClose
4852
+ *
4853
+ * Called when we are done reading from the ICAP server.
4854
+ * Either close the connection or keep it open for a future
4855
+ * transaction.
4856
+ */
4857
+static void
4858
+icapReqModKeepAliveOrClose(IcapStateData * icap)
4859
+{
4860
+    int fd = icap->icap_fd;
4861
+    debug(81, 3) ("%s:%d FD %d\n", __FILE__, __LINE__, fd);
4862
+    if (fd < 0)
4863
+	return;
4864
+    if (!icap->flags.keep_alive) {
4865
+	debug(81, 3) ("%s:%d keep_alive not set, closing\n", __FILE__,
4866
+	    __LINE__);
4867
+	comm_close(fd);
4868
+	return;
4869
+    }
4870
+    if (icap->request->content_length < 0) {
4871
+	/* no message body */
4872
+	debug(81, 3) ("%s:%d no message body\n", __FILE__, __LINE__);
4873
+	if (1 != icap->reqmod.hdr_state) {
4874
+	    /* didn't get to end of HTTP headers */
4875
+	    debug(81, 3) ("%s:%d didnt find end of headers, closing\n",
4876
+		__FILE__, __LINE__);
4877
+	    comm_close(fd);
4878
+	    return;
4879
+	}
4880
+    } else if (icap->reqmod.http_entity.bytes_read !=
4881
+	icap->request->content_length) {
4882
+	debug(81, 3) ("%s:%d bytes_read (%" PRINTF_OFF_T ") != content_length (%" PRINTF_OFF_T ")\n",
4883
+	    __FILE__, __LINE__, icap->reqmod.http_entity.bytes_read,
4884
+	    icap->request->content_length);
4885
+	/* an error */
4886
+	comm_close(fd);
4887
+	return;
4888
+    }
4889
+    debug(81, 3) ("%s:%d looks good, keeping alive\n", __FILE__, __LINE__);
4890
+    commSetDefer(fd, NULL, NULL);
4891
+    commSetTimeout(fd, -1, NULL, NULL);
4892
+    commSetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0);
4893
+    comm_remove_close_handler(fd, icapStateFree, icap);
4894
+    pconnPush(fd, icap->current_service->hostname, icap->current_service->port);
4895
+    icap->icap_fd = -1;
4896
+    icapStateFree(-1, icap);
4897
+}
4898
+
4899
+/*
4900
+ * icapReqModReadHttpHdrs
4901
+ *
4902
+ * Read the HTTP reply from the ICAP server.  Uses the values
4903
+ * from the ICAP Encapsulation header to know how many bytes
4904
+ * to read.
4905
+ */
4906
+static void
4907
+icapReqModReadHttpHdrs(int fd, void *data)
4908
+{
4909
+    IcapStateData *icap = data;
4910
+    LOCAL_ARRAY(char, tmpbuf, SQUID_TCP_SO_RCVBUF);
4911
+    int rl;
4912
+    debug(81, 3) ("icapReqModReadHttpHdrs:\n");
4913
+    assert(fd == icap->icap_fd);
4914
+    assert(icap->enc.req_hdr == 0);
4915
+    if (0 == icap->reqmod.hdr_state) {
4916
+	int expect = icapExpectedHttpReqHdrSize(icap);
4917
+	int so_far = icap->http_header_bytes_read_so_far;
4918
+	int needed = expect - so_far;
4919
+	debug(81, 3) ("expect=%d\n", expect);
4920
+	debug(81, 3) ("so_far=%d\n", so_far);
4921
+	debug(81, 3) ("needed=%d\n", needed);
4922
+	assert(needed >= 0);
4923
+	if (0 == expect) {
4924
+	    fatalf("unexpected condition in %s:%d", __FILE__, __LINE__);
4925
+	}
4926
+	rl = FD_READ_METHOD(fd, tmpbuf, needed);
4927
+	debug(81, 3) ("icapReqModReadHttpHdrs: read %d bytes\n", rl);
4928
+	if (rl < 0) {
4929
+	    fatalf("need to handle read error at %s:%d", __FILE__, __LINE__);
4930
+	}
4931
+	fd_bytes(fd, rl, FD_READ);
4932
+	kb_incr(&statCounter.icap.all.kbytes_in, rl);
4933
+	memBufAppend(&icap->reqmod.hdr_buf, tmpbuf, rl);
4934
+	icap->http_header_bytes_read_so_far += rl;
4935
+	if (rl != needed) {
4936
+	    /* still more header data to read */
4937
+	    commSetSelect(fd, COMM_SELECT_READ, icapReqModReadHttpHdrs, icap,
4938
+		0);
4939
+	    return;
4940
+	}
4941
+	icap->reqmod.hdr_state = 1;
4942
+    }
4943
+    assert(1 == icap->reqmod.hdr_state);
4944
+    debug(81, 3) ("icapReqModReadHttpHdrs: read the entire request headers\n");
4945
+    icapReqModParseHttpRequest(icap);
4946
+    if (-1 == icap->reqmod.client_fd) {
4947
+	/* we detected that the original client_side went away */
4948
+	icapReqModKeepAliveOrClose(icap);
4949
+    } else if (icap->enc.req_body > -1) {
4950
+	icap->chunk_size = 0;
4951
+	memBufDefInit(&icap->chunk_buf);
4952
+	commSetSelect(fd, COMM_SELECT_READ, icapReqModReadHttpBody, icap, 0);
4953
+    } else {
4954
+	icapReqModKeepAliveOrClose(icap);
4955
+    }
4956
+}
4957
+
4958
+
4959
+/*
4960
+ * icapReqModReadIcapPart
4961
+ *
4962
+ * Read the ICAP reply header.
4963
+ */
4964
+static void
4965
+icapReqModReadIcapPart(int fd, void *data)
4966
+{
4967
+    IcapStateData *icap = data;
4968
+    int version_major, version_minor;
4969
+    const char *str_status;
4970
+    int x;
4971
+    const char *start;
4972
+    const char *end;
4973
+    int status;
4974
+    int isIcap = 0;
4975
+    int directResponse = 0;
4976
+
4977
+    debug(81, 5) ("icapReqModReadIcapPart: FD %d httpState = %p\n", fd, data);
4978
+    statCounter.syscalls.sock.reads++;
4979
+
4980
+    x = icapReadHeader(fd, icap, &isIcap);
4981
+    if (x < 0) {
4982
+	/* Did not find a proper ICAP response */
4983
+	debug(81, 3) ("ICAP : Error path!\n");
4984
+	icapEntryError(icap, ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR,
4985
+	    errno);
4986
+	comm_close(fd);
4987
+	return;
4988
+    }
4989
+    if (x == 0) {
4990
+	/*
4991
+	 * Waiting for more headers.  Schedule new read hander, but
4992
+	 * don't reset timeout.
4993
+	 */
4994
+	commSetSelect(fd, COMM_SELECT_READ, icapReqModReadIcapPart, icap, 0);
4995
+	return;
4996
+    }
4997
+    /*
4998
+     * Parse the ICAP header
4999
+     */
5000
+    assert(icap->icap_hdr.size);
5001
+    debug(81, 3) ("Read icap header : <%s>\n", icap->icap_hdr.buf);
5002
+    if ((status =
5003
+	    icapParseStatusLine(icap->icap_hdr.buf, icap->icap_hdr.size,
5004
+		&version_major, &version_minor, &str_status)) < 0) {
5005
+	debug(81, 1) ("BAD ICAP status line <%s>\n", icap->icap_hdr.buf);
5006
+	/* is this correct in case of ICAP protocol error? */
5007
+	icapEntryError(icap, ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR,
5008
+	    errno);
5009
+	comm_close(fd);
5010
+	return;
5011
+    };
5012
+    if (200 != status && 201 != status) {
5013
+	debug(81, 1) ("Unsupported status '%d' from ICAP server\n", status);
5014
+	icapEntryError(icap, ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR,
5015
+	    errno);
5016
+	comm_close(fd);
5017
+	return;
5018
+    }
5019
+    icapSetKeepAlive(icap, icap->icap_hdr.buf);
5020
+    if (icapFindHeader(icap->icap_hdr.buf, "Encapsulated:", &start, &end)) {
5021
+	icapParseEncapsulated(icap, start, end);
5022
+    } else {
5023
+	debug(81,
5024
+	    1)
5025
+	    ("WARNING: icapReqModReadIcapPart() did not find 'Encapsulated' header\n");
5026
+    }
5027
+    if (icap->enc.res_hdr > -1)
5028
+	directResponse = 1;
5029
+    else if (icap->enc.res_body > -1)
5030
+	directResponse = 1;
5031
+    else
5032
+	directResponse = 0;
5033
+    debug(81, 3) ("icapReqModReadIcapPart: directResponse=%d\n",
5034
+	directResponse);
5035
+
5036
+    /* Check whether it is a direct reply - if so over to http part */
5037
+    if (directResponse) {
5038
+	debug(81,
5039
+	    3)
5040
+	    ("icapReqModReadIcapPart: FD %d, processing HTTP response for REQMOD!\n",
5041
+	    fd);
5042
+	/* got the reply, no need to come here again */
5043
+	icap->flags.wait_for_reply = 0;
5044
+	icap->flags.got_reply = 1;
5045
+	icapReqModHandoffRespMod(icap);
5046
+	return;
5047
+    }
5048
+    memBufDefInit(&icap->reqmod.hdr_buf);
5049
+    commSetSelect(fd, COMM_SELECT_READ, icapReqModReadHttpHdrs, icap, 0);
5050
+    return;
5051
+}
5052
+
5053
+/*
5054
+ * icapSendReqModDone
5055
+ *
5056
+ * Called after we've sent the ICAP request.  Checks for errors
5057
+ * and installs the handler functions for the next step.
5058
+ */
5059
+static void
5060
+icapSendReqModDone(int fd, char *bufnotused, size_t size, int errflag,
5061
+    void *data)
5062
+{
5063
+    IcapStateData *icap = data;
5064
+
5065
+    debug(81, 5) ("icapSendReqModDone: FD %d: size %d: errflag %d.\n",
5066
+	fd, size, errflag);
5067
+    if (size > 0) {
5068
+	fd_bytes(fd, size, FD_WRITE);
5069
+	kb_incr(&statCounter.icap.all.kbytes_out, size);
5070
+    }
5071
+    if (errflag == COMM_ERR_CLOSING)
5072
+	return;
5073
+    if (errflag) {
5074
+	debug(81, 3) ("icapSendReqModDone: unreachable=1, service=%s\n",
5075
+	    icap->current_service->uri);
5076
+	icapOptSetUnreachable(icap->current_service);
5077
+	icapEntryError(icap, ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR,
5078
+	    errno);
5079
+	comm_close(fd);
5080
+	return;
5081
+    }
5082
+    /* Schedule read reply. */
5083
+    commSetSelect(fd, COMM_SELECT_READ, icapReqModReadIcapPart, icap, 0);
5084
+    /*
5085
+     * Set the read timeout here because it hasn't been set yet.
5086
+     * We only set the read timeout after the request has been
5087
+     * fully written to the server-side.  If we start the timeout
5088
+     * after connection establishment, then we are likely to hit
5089
+     * the timeout for POST/PUT requests that have very large
5090
+     * request bodies.
5091
+     */
5092
+    commSetTimeout(fd, Config.Timeout.read, icapConnectTimeout, icap);
5093
+}
5094
+
5095
+
5096
+/*
5097
+ * icapSendReqMod
5098
+ *
5099
+ * Send the ICAP request, including HTTP request, to the ICAP server
5100
+ * after connection has been established.
5101
+ */
5102
+static void
5103
+icapSendReqMod(int fd, int status, void *data)
5104
+{
5105
+    MemBuf mb;
5106
+    MemBuf mb_hdr;
5107
+    Packer p;
5108
+    IcapStateData *icap = data;
5109
+    char *client_addr;
5110
+    int icap_fd = icap->icap_fd;
5111
+    icap_service *service;
5112
+    CWCB *theCallback;
5113
+
5114
+    debug(81, 5) ("icapSendReqMod FD %d, status %d\n", fd, status);
5115
+    icap->flags.connect_pending = 0;
5116
+
5117
+    if (COMM_OK != status) {
5118
+	debug(81, 1) ("Could not connect to ICAP server %s:%d: %s\n",
5119
+	    icap->current_service->hostname,
5120
+	    icap->current_service->port, xstrerror());
5121
+	debug(81, 3) ("icapSendReqMod: unreachable=1, service=%s\n",
5122
+	    icap->current_service->uri);
5123
+	icapOptSetUnreachable(icap->current_service);
5124
+	icapEntryError(icap, ERR_ICAP_FAILURE, HTTP_SERVICE_UNAVAILABLE, errno);
5125
+	comm_close(fd);
5126
+	return;
5127
+    }
5128
+    fd_table[fd].pconn.uses++;
5129
+    fd_table[fd].pconn.type = 2;
5130
+    if (icap->request->content_length > 0)
5131
+	theCallback = icapReqModSendBodyChunk;
5132
+    else
5133
+	theCallback = icapSendReqModDone;
5134
+
5135
+    memBufDefInit(&mb);
5136
+    memBufDefInit(&mb_hdr);
5137
+    memBufPrintf(&mb_hdr, "%s %s HTTP/%d.%d\r\n",
5138
+	RequestMethodStr[icap->request->method],
5139
+	icap->reqmod.uri,
5140
+	icap->request->http_ver.major, icap->request->http_ver.minor);
5141
+    packerToMemInit(&p, &mb_hdr);
5142
+    httpHeaderPackInto(&icap->request->header, &p);
5143
+    packerClean(&p);
5144
+    memBufAppend(&mb_hdr, crlf, 2);
5145
+    service = icap->current_service;
5146
+    assert(service);
5147
+    client_addr = inet_ntoa(icap->request->client_addr);
5148
+
5149
+    memBufPrintf(&mb, "REQMOD %s ICAP/1.0\r\n", service->uri);
5150
+    memBufPrintf(&mb, "Encapsulated: req-hdr=0");
5151
+    /* TODO: Change the offset using 'request' if needed */
5152
+    if (icap->request->content_length > 0)
5153
+	memBufPrintf(&mb, ", req-body=%d", mb_hdr.size);
5154
+    else
5155
+	memBufPrintf(&mb, ", null-body=%d", mb_hdr.size);
5156
+    memBufAppend(&mb, crlf, 2);
5157
+
5158
+    if (service->flags.need_x_client_ip && Config.icapcfg.send_client_ip)
5159
+	memBufPrintf(&mb, "X-Client-IP: %s\r\n", client_addr);
5160
+
5161
+    if (service->flags.need_x_server_ip && Config.icapcfg.send_server_ip)
5162
+        icapAddOriginIP(&mb, icap->request->host);
5163
+
5164
+    if ((service->flags.need_x_authenticated_user
5165
+	    && Config.icapcfg.send_auth_user)
5166
+	&& (icap->request->auth_user_request != NULL))
5167
+	icapAddAuthUserHeader(&mb, icap->request->auth_user_request);
5168
+    if (service->keep_alive) {
5169
+	icap->flags.keep_alive = 1;
5170
+    } else {
5171
+	icap->flags.keep_alive = 0;
5172
+	memBufAppend(&mb, "Connection: close\r\n", 19);
5173
+    }
5174
+    memBufAppend(&mb, crlf, 2);
5175
+    memBufAppend(&mb, mb_hdr.buf, mb_hdr.size);
5176
+    memBufClean(&mb_hdr);
5177
+
5178
+    debug(81, 5) ("icapSendReqMod: FD %d writing {%s}\n", icap->icap_fd,
5179
+	mb.buf);
5180
+    comm_write_mbuf(icap_fd, mb, theCallback, icap);
5181
+}
5182
+
5183
+/*
5184
+ * icapReqModStart
5185
+ *
5186
+ * Initiate an ICAP REQMOD transaction.  Create and fill in IcapStateData
5187
+ * structure and request a TCP connection to the server.
5188
+ */
5189
+IcapStateData *
5190
+icapReqModStart(icap_service *service, const char *uri, request_t * request,
5191
+    int fd, struct timeval start, struct in_addr log_addr, void *cookie)
5192
+{
5193
+    IcapStateData *icap = NULL;
5194
+
5195
+    debug(81, 3) ("icapReqModStart: type=%d\n", (int) service->type);
5196
+
5197
+    switch (service->type) {
5198
+    case ICAP_SERVICE_REQMOD_PRECACHE:
5199
+	break;
5200
+    default:
5201
+	fatalf("icapReqModStart: unsupported service type '%s'\n",
5202
+	    icap_service_type_str[service->type]);
5203
+	break;
5204
+    }
5205
+
5206
+    if (service->unreachable) {
5207
+	if (service->bypass) {
5208
+	    debug(81,
5209
+		5) ("icapReqModStart: BYPASS because service unreachable: %s\n",
5210
+		service->uri);
5211
+	    return NULL;
5212
+	} else {
5213
+	    debug(81,
5214
+		5) ("icapReqModStart: ERROR  because service unreachable: %s\n",
5215
+		service->uri);
5216
+	    return (IcapStateData *) - 1;
5217
+	}
5218
+    }
5219
+    icap = icapAllocate();
5220
+    if (!icap) {
5221
+	debug(81, 3) ("icapReqModStart: icapAllocate() failed\n");
5222
+	return NULL;
5223
+    }
5224
+    icap->current_service = service;
5225
+    icap->preview_size = service->preview;
5226
+    icap->reqmod.uri = uri;	/* XXX should be xstrdup? */
5227
+    icap->reqmod.start = start;
5228
+    icap->reqmod.log_addr = log_addr;
5229
+    icap->request = requestLink(request);
5230
+    icap->reqmod.hdr_state = 0;
5231
+    icap->reqmod.client_fd = fd;
5232
+    icap->reqmod.client_cookie = cookie;
5233
+    cbdataLock(icap->reqmod.client_cookie);
5234
+
5235
+    if (!icapConnect(icap, icapSendReqMod))
5236
+	return NULL;
5237
+
5238
+    statCounter.icap.all.requests++;
5239
+    debug(81, 3) ("icapReqModStart: returning %p\n", icap);
5240
+    return icap;
5241
+}
5242
+
5243
+/*
5244
+ * icapReqModSendBodyChunk
5245
+ *
5246
+ * A "comm_write" callback.  This is called after comm_write() does
5247
+ * its job to let us know how things went.  If there are no errors,
5248
+ * get another chunk of the body from client_side.
5249
+ */
5250
+static void
5251
+icapReqModSendBodyChunk(int fd, char *bufnotused, size_t size, int errflag,
5252
+    void *data)
5253
+{
5254
+    IcapStateData *icap = data;
5255
+    debug(81, 3) ("icapReqModSendBodyChunk: FD %d wrote %d errflag %d.\n",
5256
+	fd, (int) size, errflag);
5257
+    if (errflag == COMM_ERR_CLOSING)
5258
+	return;
5259
+    if (errflag) {
5260
+	icapEntryError(icap, ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR,
5261
+	    errno);
5262
+	comm_close(fd);
5263
+	return;
5264
+    }
5265
+    clientReadBody(icap->request,
5266
+	memAllocate(MEM_8K_BUF), 8192, icapReqModBodyHandler, icap);
5267
+}
5268
+
5269
+/*
5270
+ * icapReqModBodyHandler
5271
+ *
5272
+ * Called after Squid gets a chunk of the request entity from the
5273
+ * client side.  The body is chunkified and passed to comm_write.
5274
+ * The comm_write callback depends on whether or not this is the
5275
+ * last chunk.
5276
+ */
5277
+static void
5278
+icapReqModBodyHandler(char *buf, ssize_t size, void *data)
5279
+{
5280
+    IcapStateData *icap = data;
5281
+    MemBuf mb;
5282
+    CWCB *theCallback = icapReqModSendBodyChunk;
5283
+    if (size < 0) {
5284
+	debug(81, 1) ("icapReqModBodyHandler: %s\n", xstrerror());
5285
+	memFree8K(buf);
5286
+	return;
5287
+    }
5288
+    memBufDefInit(&mb);
5289
+    debug(81, 3) ("icapReqModBodyHandler: writing chunk size %d\n", size);
5290
+    memBufPrintf(&mb, "%x\r\n", size);
5291
+    if (size)
5292
+	memBufAppend(&mb, buf, size);
5293
+    else
5294
+	theCallback = icapSendReqModDone;
5295
+    memBufAppend(&mb, crlf, 2);
5296
+    memFree8K(buf);
5297
+    comm_write_mbuf(icap->icap_fd, mb, theCallback, icap);
5298
+}
5299
+
5300
+/*
5301
+ * icapReqModReadHttpBody
5302
+ *
5303
+ * The read handler for the client's HTTP connection when reading
5304
+ * message bodies.  Called by comm_select().
5305
+ */
5306
+static void
5307
+icapReqModReadHttpBody(int fd, void *data)
5308
+{
5309
+    IcapStateData *icap = data;
5310
+    int len;
5311
+    debug(81, 3) ("icapReqModReadHttpBody: FD %d called\n", fd);
5312
+    len = memBufRead(fd, &icap->chunk_buf);
5313
+    debug(81, 3) ("icapReqModReadHttpBody: read returns %d\n", len);
5314
+    if (len < 0) {
5315
+	debug(81, 3) ("icapReqModReadHttpBody: FD %d %s\n", fd, xstrerror());
5316
+	if (!ignoreErrno(errno))
5317
+	    icap->flags.reqmod_http_entity_eof = 1;
5318
+    } else if (0 == len) {
5319
+	debug(81, 3) ("icapReqModReadHttpBody: FD %d EOF\n", fd);
5320
+	icap->flags.reqmod_http_entity_eof = 1;
5321
+    } else {
5322
+	fd_bytes(fd, len, FD_READ);
5323
+	kb_incr(&statCounter.icap.all.kbytes_in, len);
5324
+	icap->reqmod.http_entity.bytes_read +=
5325
+	    icapParseChunkedBody(icap,
5326
+	    icapReqModMemBufAppend, &icap->reqmod.http_entity.buf);
5327
+    }
5328
+    if (icap->reqmod.http_entity.bytes_read >= icap->request->content_length)
5329
+	icap->flags.reqmod_http_entity_eof = 1;
5330
+
5331
+    if (!icap->flags.reqmod_http_entity_eof)
5332
+	commSetSelect(fd, COMM_SELECT_READ, icapReqModReadHttpBody, icap, 0);
5333
+    /*
5334
+     * Notify the other side if it is waiting for data from us
5335
+     */
5336
+    debug(81, 3) ("%s:%d http_entity.callback=%p\n", __FILE__, __LINE__,
5337
+	icap->reqmod.http_entity.callback);
5338
+    debug(81, 3) ("%s:%d http_entity.buf.size=%d\n", __FILE__, __LINE__,
5339
+	icap->reqmod.http_entity.buf.size);
5340
+    if (icap->reqmod.http_entity.callback && icap->reqmod.http_entity.buf.size) {
5341
+	icapReqModPassHttpBody(icap,
5342
+	    icap->reqmod.http_entity.callback_buf,
5343
+	    icap->reqmod.http_entity.callback_bufsize,
5344
+	    icap->reqmod.http_entity.callback,
5345
+	    icap->reqmod.http_entity.callback_data);
5346
+	icap->reqmod.http_entity.callback = NULL;
5347
+	cbdataUnlock(icap->reqmod.http_entity.callback_data);
5348
+
5349
+    }
5350
+}
5351
+
5352
+/*
5353
+ * icapReqModPassHttpBody
5354
+ *
5355
+ * Called from http.c after request headers have been sent.
5356
+ * This function feeds the http.c module chunks of the request
5357
+ * body that were stored in the http_entity.buf MemBuf.
5358
+ */
5359
+static void
5360
+icapReqModPassHttpBody(IcapStateData * icap, char *buf, size_t size,
5361
+    CBCB * callback, void *cbdata)
5362
+{
5363
+    debug(81, 3) ("icapReqModPassHttpBody: called\n");
5364
+    if (!buf) {
5365
+	debug(81, 1) ("icapReqModPassHttpBody: FD %d called with %p, %d, %p (request aborted)\n",
5366
+	    icap->icap_fd, buf, (int) size, cbdata);
5367
+	comm_close(icap->icap_fd);
5368
+	return;
5369
+    }
5370
+    if (!cbdataValid(cbdata)) {
5371
+	debug(81,
5372
+	    1)
5373
+	    ("icapReqModPassHttpBody: FD %d callback data invalid, closing\n",
5374
+	    icap->icap_fd);
5375
+	comm_close(icap->icap_fd);	/*It is better to be sure that the connection will be  closed..... */
5376
+	/*icapReqModKeepAliveOrClose(icap); */
5377
+	return;
5378
+    }
5379
+    debug(81, 3) ("icapReqModPassHttpBody: entity buf size = %d\n",
5380
+	icap->reqmod.http_entity.buf.size);
5381
+    if (icap->reqmod.http_entity.buf.size) {
5382
+	int copy_sz = icap->reqmod.http_entity.buf.size;
5383
+	if (copy_sz > size)
5384
+	    copy_sz = size;
5385
+	xmemcpy(buf, icap->reqmod.http_entity.buf.buf, copy_sz);
5386
+	/* XXX don't let Alex see this ugliness */
5387
+	xmemmove(icap->reqmod.http_entity.buf.buf,
5388
+	    icap->reqmod.http_entity.buf.buf + copy_sz,
5389
+	    icap->reqmod.http_entity.buf.size - copy_sz);
5390
+	icap->reqmod.http_entity.buf.size -= copy_sz;
5391
+	debug(81, 3) ("icapReqModPassHttpBody: giving %d bytes to other side\n",
5392
+	    copy_sz);
5393
+	callback(buf, copy_sz, cbdata);
5394
+	debug(81, 3) ("icapReqModPassHttpBody: entity buf size now = %d\n",
5395
+	    icap->reqmod.http_entity.buf.size);
5396
+	return;
5397
+    }
5398
+    if (icap->flags.reqmod_http_entity_eof) {
5399
+	debug(81, 3) ("icapReqModPassHttpBody: signalling EOF\n");
5400
+	callback(buf, 0, cbdata);
5401
+	icapReqModKeepAliveOrClose(icap);
5402
+	return;
5403
+    }
5404
+    /*
5405
+     * We have no data for the other side at this point.  Save all
5406
+     * these values and use them when we do have data.
5407
+     */
5408
+    assert(NULL == icap->reqmod.http_entity.callback);
5409
+    icap->reqmod.http_entity.callback = callback;
5410
+    icap->reqmod.http_entity.callback_data = cbdata;
5411
+    icap->reqmod.http_entity.callback_buf = buf;
5412
+    icap->reqmod.http_entity.callback_bufsize = size;
5413
+    cbdataLock(icap->reqmod.http_entity.callback_data);
5414
+}
5415
+
5416
+/*
5417
+ * Body reader handler for use with request->body_reader function
5418
+ * Simple a wrapper for icapReqModPassHttpBody function
5419
+ */
5420
+
5421
+static void
5422
+icapReqModBodyReader(request_t * request, char *buf, size_t size,
5423
+    CBCB * callback, void *cbdata)
5424
+{
5425
+    IcapStateData *icap = request->body_reader_data;
5426
+    icapReqModPassHttpBody(icap, buf, size, callback, cbdata);
5427
+}
5428
+
5429
+/*
5430
+ * icapReqModMemBufAppend
5431
+ *
5432
+ * stupid wrapper to eliminate compiler warnings
5433
+ */
5434
+static void
5435
+icapReqModMemBufAppend(void *data, const char *buf, ssize_t size)
5436
+{
5437
+    memBufAppend(data, buf, size);
5438
+}
5439
Index: src/icap_respmod.c
5440
===================================================================
5441
RCS file: src/icap_respmod.c
5442
diff -N src/icap_respmod.c
5443
--- /dev/null	1 Jan 1970 00:00:00 -0000
5444
+++ src/icap_respmod.c	25 May 2006 16:04:55 -0000	1.1.2.65
5445
@@ -0,0 +1,1055 @@
5446
+
5447
+/*
5448
+ * $Id$
5449
+ *
5450
+ * DEBUG: section 81    Internet Content Adaptation Protocol (ICAP) Client
5451
+ * AUTHOR: Geetha Manjunath, Hewlett Packard Company
5452
+ *
5453
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
5454
+ * ----------------------------------------------------------
5455
+ *
5456
+ *  Squid is the result of efforts by numerous individuals from
5457
+ *  the Internet community; see the CONTRIBUTORS file for full
5458
+ *  details.   Many organizations have provided support for Squid's
5459
+ *  development; see the SPONSORS file for full details.  Squid is
5460
+ *  Copyrighted (C) 2001 by the Regents of the University of
5461
+ *  California; see the COPYRIGHT file for full details.  Squid
5462
+ *  incorporates software developed and/or copyrighted by other
5463
+ *  sources; see the CREDITS file for full details.
5464
+ *
5465
+ *  This program is free software; you can redistribute it and/or modify
5466
+ *  it under the terms of the GNU General Public License as published by
5467
+ *  the Free Software Foundation; either version 2 of the License, or
5468
+ *  (at your option) any later version.
5469
+ *  
5470
+ *  This program is distributed in the hope that it will be useful,
5471
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
5472
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
5473
+ *  GNU General Public License for more details.
5474
+ *  
5475
+ *  You should have received a copy of the GNU General Public License
5476
+ *  along with this program; if not, write to the Free Software
5477
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
5478
+ *
5479
+ */
5480
+
5481
+#include "squid.h"
5482
+
5483
+static CWCB icapSendRespModDone;
5484
+static PF icapRespModGobble;
5485
+extern PF icapReadReply;
5486
+static PF icapRespModReadReply;
5487
+static int icapReadReply2(IcapStateData * icap);
5488
+static void icapReadReply3(IcapStateData * icap);
5489
+
5490
+#define EXPECTED_ICAP_HEADER_LEN 256
5491
+const char *crlf = "\r\n";
5492
+
5493
+static void
5494
+getICAPRespModString(MemBuf * mb, int o1, int o2, int o3,
5495
+    const char *client_addr, IcapStateData * icap, const icap_service * service)
5496
+{
5497
+    memBufPrintf(mb, "RESPMOD %s ICAP/1.0\r\nEncapsulated:", service->uri);
5498
+    if (o1 >= 0)
5499
+	memBufPrintf(mb, " req-hdr=%1d", o1);
5500
+    if (o2 >= 0)
5501
+	memBufPrintf(mb, ", res-hdr=%1d", o2);
5502
+    if (o3 >= 0)
5503
+	memBufPrintf(mb, ", res-body=%1d", o3);
5504
+    else
5505
+	memBufPrintf(mb, ", null-body=%1d", -o3);
5506
+    memBufPrintf(mb, crlf);
5507
+
5508
+    if (service->flags.need_x_client_ip && Config.icapcfg.send_client_ip) {
5509
+	memBufPrintf(mb, "X-Client-IP: %s\r\n", client_addr);
5510
+    }
5511
+
5512
+    if (service->flags.need_x_server_ip && Config.icapcfg.send_server_ip)
5513
+        icapAddOriginIP(mb, icap->request->host);
5514
+
5515
+    if ((service->flags.need_x_authenticated_user
5516
+	    && Config.icapcfg.send_auth_user)
5517
+	&& (icap->request->auth_user_request != NULL)) {
5518
+	icapAddAuthUserHeader(mb, icap->request->auth_user_request);
5519
+    }
5520
+#if NOT_YET_FINISHED
5521
+    if (Config.icapcfg.trailers) {
5522
+	memBufPrintf(mb, "X-TE: trailers\r\n");
5523
+    }
5524
+#endif
5525
+}
5526
+
5527
+static int
5528
+buildRespModHeader(MemBuf * mb, IcapStateData * icap, char *buf,
5529
+    ssize_t len, int theEnd)
5530
+{
5531
+    MemBuf mb_hdr;
5532
+    char *client_addr;
5533
+    int o2 = 0;
5534
+    int o3 = 0;
5535
+    int hlen;
5536
+    int consumed;
5537
+    icap_service *service;
5538
+    HttpReply *r;
5539
+
5540
+    if (memBufIsNull(&icap->respmod.req_hdr_copy))
5541
+	memBufDefInit(&icap->respmod.req_hdr_copy);
5542
+
5543
+    memBufAppend(&icap->respmod.req_hdr_copy, buf, len);
5544
+
5545
+    if (icap->respmod.req_hdr_copy.size > 4 && strncmp(icap->respmod.req_hdr_copy.buf, "HTTP/", 5)) {
5546
+	debug(81, 3) ("buildRespModHeader: Non-HTTP-compliant header: '%s'\n", buf);
5547
+	/*
5548
+	 *Possible we can consider that we did not have http responce headers 
5549
+	 *(maybe HTTP 0.9 protocol), lets returning -1...
5550
+	 */
5551
+	consumed = -1;
5552
+	o2 = -1;
5553
+	memBufDefInit(&mb_hdr);
5554
+	httpBuildRequestPrefix(icap->request, icap->request,
5555
+			       icap->respmod.entry, &mb_hdr, icap->http_flags);
5556
+	o3 = mb_hdr.size;
5557
+    } else {
5558
+
5559
+	hlen = headersEnd(icap->respmod.req_hdr_copy.buf,
5560
+	    icap->respmod.req_hdr_copy.size);
5561
+	debug(81, 3) ("buildRespModHeader: headersEnd = %d(%s)\n", hlen, buf);
5562
+	if (0 == hlen)
5563
+	    return 0;
5564
+
5565
+	/*
5566
+	 * calc how many bytes from this 'buf' went towards the
5567
+	 * reply header.
5568
+	 */
5569
+	consumed = hlen - (icap->respmod.req_hdr_copy.size - len);
5570
+	debug(81, 3) ("buildRespModHeader: consumed = %d\n", consumed);
5571
+
5572
+
5573
+	/*
5574
+	 * now, truncate our req_hdr_copy at the header end.
5575
+	 * this 'if' statement might be unncessary?
5576
+	 */
5577
+	if (hlen < icap->respmod.req_hdr_copy.size)
5578
+	    icap->respmod.req_hdr_copy.size = hlen;
5579
+
5580
+	/* Copy request header */
5581
+	memBufDefInit(&mb_hdr);
5582
+	httpBuildRequestPrefix(icap->request, icap->request,
5583
+	    icap->respmod.entry, &mb_hdr, icap->http_flags);
5584
+	o2 = mb_hdr.size;
5585
+
5586
+    	/* Copy response header - Append to request header mbuffer */
5587
+	memBufAppend(&mb_hdr,
5588
+		     icap->respmod.req_hdr_copy.buf, icap->respmod.req_hdr_copy.size);
5589
+	o3 = mb_hdr.size;
5590
+    }
5591
+
5592
+    service = icap->current_service;
5593
+    assert(service);
5594
+    client_addr = inet_ntoa(icap->request->client_addr);
5595
+
5596
+    r = httpReplyCreate();
5597
+    httpReplyParse(r, icap->respmod.req_hdr_copy.buf,
5598
+	icap->respmod.req_hdr_copy.size);
5599
+    icap->respmod.res_body_sz = httpReplyBodySize(icap->request->method, r);
5600
+    httpReplyDestroy(r);
5601
+    if (icap->respmod.res_body_sz)
5602
+	getICAPRespModString(mb, 0, o2, o3, client_addr, icap, service);
5603
+    else
5604
+	getICAPRespModString(mb, 0, o2, -o3, client_addr, icap, service);
5605
+    if (Config.icapcfg.preview_enable)
5606
+	if (icap->preview_size >= 0) {
5607
+	    memBufPrintf(mb, "Preview: %d\r\n", icap->preview_size);
5608
+	    icap->flags.preview_done = 0;
5609
+	}
5610
+    if (service->keep_alive) {
5611
+	icap->flags.keep_alive = 1;
5612
+	memBufAppend(mb, "Connection: keep-alive\r\n", 24);
5613
+    } else {
5614
+	icap->flags.keep_alive = 0;
5615
+	memBufAppend(mb, "Connection: close\r\n", 19);
5616
+    }
5617
+    memBufAppend(mb, crlf, 2);
5618
+    memBufAppend(mb, mb_hdr.buf, mb_hdr.size);
5619
+    memBufClean(&mb_hdr);
5620
+
5621
+
5622
+    return consumed;
5623
+}
5624
+
5625
+
5626
+void
5627
+icapSendRespMod(IcapStateData * icap, char *buf, int len, int theEnd)
5628
+{
5629
+    MemBuf mb;
5630
+#if ICAP_PREVIEW
5631
+    int size;
5632
+    const int preview_size = icap->preview_size;
5633
+#endif
5634
+    debug(81, 5) ("icapSendRespMod: FD %d, len %d, theEnd %d\n",
5635
+	icap->icap_fd, len, theEnd);
5636
+
5637
+    if (icap->flags.no_content) {
5638
+	/*
5639
+	 * ICAP server said there are no modifications to make, so
5640
+	 * just append this data to the StoreEntry
5641
+	 */
5642
+	if (icap->respmod.resp_copy.size) {
5643
+	    /*
5644
+	     * first copy the data that we already sent to the ICAP server
5645
+	     */
5646
+	    memBufAppend(&icap->chunk_buf,
5647
+		icap->respmod.resp_copy.buf, icap->respmod.resp_copy.size);
5648
+	    icap->respmod.resp_copy.size = 0;
5649
+	}
5650
+	debug(81, 5) ("icapSendRepMod: len=%d theEnd=%d write_pending=%d\n",
5651
+	    len, theEnd, icap->flags.write_pending);
5652
+	if (len) {
5653
+	    /*
5654
+	     * also copy any new data from the HTTP side
5655
+	     */
5656
+	    memBufAppend(&icap->chunk_buf, buf, len);
5657
+	}
5658
+	(void) icapReadReply2(icap);
5659
+	return;
5660
+    }
5661
+    if (theEnd) {
5662
+	if (icap->respmod.res_body_sz)
5663
+	    icap->flags.send_zero_chunk = 1;
5664
+	icap->flags.http_server_eof = 1;
5665
+    }
5666
+    /*
5667
+     * httpReadReply is going to call us with a chunk and then
5668
+     * right away again with an EOF if httpPconnTransferDone() is true.
5669
+     * Since the first write is already dispatched, we'll have to 
5670
+     * hack this in somehow.
5671
+     */
5672
+    if (icap->flags.write_pending) {
5673
+	debug(81, 3) ("icapSendRespMod: oops, write_pending=1\n");
5674
+	assert(theEnd);
5675
+	assert(len == 0);
5676
+	return;
5677
+    }
5678
+    if (!cbdataValid(icap)) {
5679
+	debug(81, 3) ("icapSendRespMod: failed to establish connection?\n");
5680
+	return;
5681
+    }
5682
+    memBufDefInit(&mb);
5683
+
5684
+#if SUPPORT_ICAP_204 || ICAP_PREVIEW
5685
+    /*
5686
+     * make a copy of the response in case ICAP server gives us a 204
5687
+     */
5688
+    /*
5689
+     * This piece of code is problematic for 204 responces outside preview.
5690
+     * The icap->respmod.resp_copy continues to filled until we had responce
5691
+     * If the icap server waits to gets all data before sends its responce 
5692
+     * then we are puting all downloading object to the main system memory.
5693
+     * My opinion is that 204 responces outside preview must be disabled .....
5694
+     * /chtsanti
5695
+     */
5696
+
5697
+    if (len && icap->flags.copy_response) {
5698
+	if (memBufIsNull(&icap->respmod.resp_copy))
5699
+	    memBufDefInit(&icap->respmod.resp_copy);
5700
+	memBufAppend(&icap->respmod.resp_copy, buf, len);
5701
+    }
5702
+#endif
5703
+
5704
+    if (icap->sc == 0) {
5705
+        // http connection has been closed without sending us anything
5706
+        if(len == 0 && theEnd == 1) {
5707
+	    ErrorState *err;
5708
+	    err = errorCon(ERR_INVALID_RESP, HTTP_BAD_GATEWAY);
5709
+	    err->request = requestLink(icap->request);
5710
+	    errorAppendEntry(icap->respmod.entry, err);
5711
+	    comm_close(icap->icap_fd);
5712
+	    return;
5713
+        }
5714
+
5715
+	/* No data sent yet. Start with headers */
5716
+	if ((icap->sc = buildRespModHeader(&mb, icap, buf, len, theEnd)) > 0) {
5717
+	    buf += icap->sc;
5718
+	    len -= icap->sc;
5719
+	}
5720
+	/*
5721
+	 * Then we do not have http responce headers. All data (previous and those in buf)
5722
+	 * now are exist to icap->respmod.req_hdr_copy. Lets get them back.......
5723
+	 */
5724
+	if (icap->sc < 0) {
5725
+	    memBufAppend(&icap->respmod.buffer,
5726
+		icap->respmod.req_hdr_copy.buf,
5727
+		icap->respmod.req_hdr_copy.size);
5728
+	    icap->sc = icap->respmod.req_hdr_copy.size;
5729
+	    icap->respmod.req_hdr_copy.size = 0;
5730
+	    buf = NULL;
5731
+	    len = 0;
5732
+	}
5733
+    }
5734
+    if (0 == icap->sc) {
5735
+	/* check again; bail if we're not ready to send ICAP/HTTP hdrs */
5736
+	debug(81, 5) ("icapSendRespMod: dont have full HTTP response hdrs\n");
5737
+	memBufClean(&mb);
5738
+	return;
5739
+    }
5740
+#if ICAP_PREVIEW
5741
+    if (preview_size < 0 || !Config.icapcfg.preview_enable)	/* preview feature off */
5742
+	icap->flags.preview_done = 1;
5743
+
5744
+    if (!icap->flags.preview_done) {
5745
+	/* preview not yet sent */
5746
+	if (icap->sc > 0 && icap->respmod.buffer.size <= preview_size
5747
+	    && len > 0) {
5748
+	    /* Try to collect at least preview_size+1 bytes */
5749
+	    /* By collecting one more byte than needed for preview we know best */
5750
+	    /* whether we have to send the ieof chunk extension */
5751
+	    size = icap->respmod.buffer.size + len;
5752
+	    if (size > preview_size + 1)
5753
+		size = preview_size + 1;
5754
+	    size -= icap->respmod.buffer.size;
5755
+	    debug(81,
5756
+		3)
5757
+		("icapSendRespMod: FD %d: copy %d more bytes to preview buffer.\n",
5758
+		icap->icap_fd, size);
5759
+	    memBufAppend(&icap->respmod.buffer, buf, size);
5760
+	    buf = ((char *) buf) + size;
5761
+	    len -= size;
5762
+	}
5763
+	if (icap->respmod.buffer.size > preview_size || theEnd) {
5764
+	    /* we got enough bytes for preview or this is the last call */
5765
+	    /* add preview preview now */
5766
+	    if (icap->respmod.buffer.size > 0) {
5767
+		size = icap->respmod.buffer.size;
5768
+		if (size > preview_size)
5769
+		    size = preview_size;
5770
+		memBufPrintf(&mb, "%x\r\n", size);
5771
+		memBufAppend(&mb, icap->respmod.buffer.buf, size);
5772
+		memBufAppend(&mb, crlf, 2);
5773
+		icap->sc += size;
5774
+	    }
5775
+	    if (icap->respmod.buffer.size <= preview_size) {
5776
+		/* content length is less than preview size+1 */
5777
+		if (icap->respmod.res_body_sz)
5778
+		    memBufAppend(&mb, "0; ieof\r\n\r\n", 11);
5779
+		memBufReset(&icap->respmod.buffer);	/* will now be used for other data */
5780
+	    } else {
5781
+		char ch;
5782
+		memBufAppend(&mb, "0\r\n\r\n", 5);
5783
+		/* end of preview, wait for continue or 204 signal */
5784
+		/* copy the extra byte and all other data to the icap buffer */
5785
+		/* so that it can be handled next time */
5786
+		ch = icap->respmod.buffer.buf[preview_size];
5787
+		memBufReset(&icap->respmod.buffer);	/* will now be used for other data */
5788
+		memBufAppend(&icap->respmod.buffer, &ch, 1);
5789
+		debug(81,
5790
+		    3)
5791
+		    ("icapSendRespMod: FD %d: sending preview and keeping %d bytes in internal buf.\n",
5792
+		    icap->icap_fd, len + 1);
5793
+		if (len > 0)
5794
+		    memBufAppend(&icap->respmod.buffer, buf, len);
5795
+	    }
5796
+	    icap->flags.preview_done = 1;
5797
+	    icap->flags.wait_for_preview_reply = 1;
5798
+	}
5799
+    } else if (icap->flags.wait_for_preview_reply) {
5800
+	/* received new data while waiting for preview response */
5801
+	/* add data to internal buffer and send later */
5802
+	debug(81,
5803
+	    3)
5804
+	    ("icapSendRespMod: FD %d: add %d more bytes to internal buf while waiting for preview-response.\n",
5805
+	    icap->icap_fd, len);
5806
+	if (len > 0)
5807
+	    memBufAppend(&icap->respmod.buffer, buf, len);
5808
+	/* do not send any data now while waiting for preview response */
5809
+	/* but prepare for read more data on the HTTP connection */
5810
+	memBufClean(&mb);
5811
+	return;
5812
+    } else
5813
+#endif
5814
+    {
5815
+	/* after preview completed and ICAP preview response received */
5816
+	/* there may still be some data in the buffer */
5817
+	if (icap->respmod.buffer.size > 0) {
5818
+	    memBufPrintf(&mb, "%x\r\n", icap->respmod.buffer.size);
5819
+	    memBufAppend(&mb, icap->respmod.buffer.buf,
5820
+		icap->respmod.buffer.size);
5821
+	    memBufAppend(&mb, crlf, 2);
5822
+	    icap->sc += icap->respmod.buffer.size;
5823
+	    memBufReset(&icap->respmod.buffer);
5824
+	}
5825
+	if (len > 0) {
5826
+	    memBufPrintf(&mb, "%x\r\n", len);
5827
+	    memBufAppend(&mb, buf, len);
5828
+	    memBufAppend(&mb, crlf, 2);
5829
+	    icap->sc += len;
5830
+	}
5831
+	if (icap->flags.send_zero_chunk) {
5832
+	    /* send zero end chunk */
5833
+	    icap->flags.send_zero_chunk = 0;
5834
+	    icap->flags.http_server_eof = 1;
5835
+	    memBufAppend(&mb, "0\r\n\r\n", 5);
5836
+	}
5837
+	/* wait for data coming from ICAP server as soon as we sent something */
5838
+	/* but of course only until we got the response header */
5839
+	if (!icap->flags.got_reply)
5840
+	    icap->flags.wait_for_reply = 1;
5841
+    }
5842
+    commSetTimeout(icap->icap_fd, -1, NULL, NULL);
5843
+
5844
+    if (!mb.size) {
5845
+	memBufClean(&mb);
5846
+	return;
5847
+    }
5848
+    debug(81, 5) ("icapSendRespMod: FD %d writing {%s}\n", icap->icap_fd,
5849
+	mb.buf);
5850
+    icap->flags.write_pending = 1;
5851
+    comm_write_mbuf(icap->icap_fd, mb, icapSendRespModDone, icap);
5852
+}
5853
+
5854
+static void
5855
+icapRespModReadReply(int fd, void *data)
5856
+{
5857
+    IcapStateData *icap = data;
5858
+    int version_major, version_minor;
5859
+    const char *str_status;
5860
+    int x;
5861
+    int status = 0;
5862
+    int isIcap = 0;
5863
+    int directResponse = 0;
5864
+    ErrorState *err;
5865
+    const char *start;
5866
+    const char *end;
5867
+
5868
+    debug(81, 5) ("icapRespModReadReply: FD %d data = %p\n", fd, data);
5869
+    statCounter.syscalls.sock.reads++;
5870
+
5871
+    x = icapReadHeader(fd, icap, &isIcap);
5872
+    if (x < 0) {
5873
+	/* Did not find a proper ICAP response */
5874
+	debug(81, 3) ("ICAP : Error path!\n");
5875
+	err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
5876
+	err->request = requestLink(icap->request);
5877
+	err->xerrno = errno;
5878
+	errorAppendEntry(icap->respmod.entry, err);
5879
+	comm_close(fd);
5880
+	return;
5881
+    }
5882
+    if (x == 0) {
5883
+	/*
5884
+	 * Waiting for more headers.  Schedule new read hander, but
5885
+	 * don't reset timeout.
5886
+	 */
5887
+	commSetSelect(fd, COMM_SELECT_READ, icapRespModReadReply, icap, 0);
5888
+	return;
5889
+    }
5890
+    /*
5891
+     * Parse the ICAP header
5892
+     */
5893
+    assert(icap->icap_hdr.size);
5894
+    debug(81, 3) ("Parse icap header : <%s>\n", icap->icap_hdr.buf);
5895
+    if ((status =
5896
+	    icapParseStatusLine(icap->icap_hdr.buf, icap->icap_hdr.size,
5897
+		&version_major, &version_minor, &str_status)) < 0) {
5898
+	debug(81, 1) ("BAD ICAP status line <%s>\n", icap->icap_hdr.buf);
5899
+	/* is this correct in case of ICAP protocol error? */
5900
+	err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
5901
+	err->request = requestLink(icap->request);
5902
+	err->xerrno = errno;
5903
+	errorAppendEntry(icap->respmod.entry, err);
5904
+	comm_close(fd);
5905
+	return;
5906
+    };
5907
+    /*  OK here we have responce. Lets stop filling the 
5908
+     *  icap->respmod.resp_copy buffer ....
5909
+     */
5910
+    icap->flags.copy_response = 0;
5911
+
5912
+    icapSetKeepAlive(icap, icap->icap_hdr.buf);
5913
+#if ICAP_PREVIEW
5914
+    if (icap->flags.wait_for_preview_reply) {
5915
+	if (100 == status) {
5916
+	    debug(81, 5) ("icapRespModReadReply: 100 Continue received\n");
5917
+	    icap->flags.wait_for_preview_reply = 0;
5918
+	    /* if http_server_eof
5919
+	     * call again icapSendRespMod to handle data that
5920
+	     * was received while waiting for this ICAP response
5921
+	     * else let http to call icapSendRespMod when new data arrived
5922
+	     */
5923
+	    if (icap->flags.http_server_eof)
5924
+		icapSendRespMod(icap, NULL, 0, 0);
5925
+	    /*
5926
+	     * reset the header to send the rest of the preview
5927
+	     */
5928
+	    if (!memBufIsNull(&icap->icap_hdr))
5929
+		memBufReset(&icap->icap_hdr);
5930
+
5931
+	    /*We do n't need it any more ....... */
5932
+	    if (!memBufIsNull(&icap->respmod.resp_copy))
5933
+		memBufClean(&icap->respmod.resp_copy);
5934
+
5935
+	    return;
5936
+	}
5937
+	if (204 == status) {
5938
+	    debug(81,
5939
+		5) ("icapRespModReadReply: 204 No modification received\n");
5940
+	    icap->flags.wait_for_preview_reply = 0;
5941
+	}
5942
+    }
5943
+#endif /*ICAP_PREVIEW */
5944
+
5945
+#if SUPPORT_ICAP_204 || ICAP_PREVIEW
5946
+    if (204 == status) {
5947
+	debug(81, 3) ("got 204 status from ICAP server\n");
5948
+	debug(81, 3) ("setting icap->flags.no_content\n");
5949
+	icap->flags.no_content = 1;
5950
+	/*
5951
+	 * copy the response already written to the ICAP server
5952
+	 */
5953
+	debug(81, 3) ("copying %d bytes from resp_copy to chunk_buf\n",
5954
+	    icap->respmod.resp_copy.size);
5955
+	memBufAppend(&icap->chunk_buf,
5956
+	    icap->respmod.resp_copy.buf, icap->respmod.resp_copy.size);
5957
+	icap->respmod.resp_copy.size = 0;
5958
+	if (icapReadReply2(icap) < 0)
5959
+	    comm_close(fd);
5960
+	/*
5961
+	 * XXX ideally want to clean icap->respmod.resp_copy here
5962
+	 * XXX ideally want to "close" ICAP server connection here
5963
+	 * OK do it....
5964
+	 */
5965
+	if (!memBufIsNull(&icap->respmod.resp_copy))
5966
+	    memBufClean(&icap->respmod.resp_copy);
5967
+	return;
5968
+    }
5969
+#endif
5970
+    if (200 != status && 201 != status) {
5971
+	debug(81, 1) ("Unsupported status '%d' from ICAP server\n", status);
5972
+	/* Did not find a proper ICAP response */
5973
+	err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
5974
+	err->request = requestLink(icap->request);
5975
+	err->xerrno = errno;
5976
+	errorAppendEntry(icap->respmod.entry, err);
5977
+	comm_close(fd);
5978
+	return;
5979
+    }
5980
+    if (icapFindHeader(icap->icap_hdr.buf, "Encapsulated:", &start, &end)) {
5981
+	icapParseEncapsulated(icap, start, end);
5982
+    } else {
5983
+	debug(81,
5984
+	    1)
5985
+	    ("WARNING: icapRespModReadReply() did not find 'Encapsulated' header\n");
5986
+    }
5987
+    if (icap->enc.res_hdr > -1)
5988
+	directResponse = 1;
5989
+    else if (icap->enc.res_body > -1)
5990
+	directResponse = 1;
5991
+    else
5992
+	directResponse = 0;
5993
+
5994
+    /*
5995
+     * "directResponse" is the normal case here.  If we don't have
5996
+     * a response header or body, it is an error.
5997
+     */
5998
+    if (!directResponse) {
5999
+	/* Did not find a proper ICAP response */
6000
+	debug(81, 3) ("ICAP : Error path!\n");
6001
+	err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
6002
+	err->request = requestLink(icap->request);
6003
+	err->xerrno = errno;
6004
+	errorAppendEntry(icap->respmod.entry, err);
6005
+	comm_close(fd);
6006
+	return;
6007
+    }
6008
+    /* got the reply, no need to come here again */
6009
+    icap->flags.wait_for_reply = 0;
6010
+    icap->flags.got_reply = 1;
6011
+    /* Next, gobble any data before the HTTP response starts */
6012
+    if (icap->enc.res_hdr > -1)
6013
+	icap->bytes_to_gobble = icap->enc.res_hdr;
6014
+    commSetSelect(fd, COMM_SELECT_READ, icapRespModGobble, icap, 0);
6015
+}
6016
+
6017
+
6018
+/*
6019
+ * Gobble up (read) some bytes until we get to the start of the body
6020
+ */
6021
+static void
6022
+icapRespModGobble(int fd, void *data)
6023
+{
6024
+    IcapStateData *icap = data;
6025
+    int len;
6026
+    LOCAL_ARRAY(char, junk, SQUID_TCP_SO_RCVBUF);
6027
+    debug(81, 3) ("icapRespModGobble: FD %d gobbling %d bytes\n", fd,
6028
+	icap->bytes_to_gobble);
6029
+    len = FD_READ_METHOD(fd, junk, icap->bytes_to_gobble);
6030
+    debug(81, 3) ("icapRespModGobble: gobbled %d bytes\n", len);
6031
+    if (len < 0) {
6032
+	/* XXX error */
6033
+	abort();
6034
+    }
6035
+    icap->bytes_to_gobble -= len;
6036
+    if (icap->bytes_to_gobble)
6037
+	commSetSelect(fd, COMM_SELECT_READ, icapRespModGobble, icap, 0);
6038
+    else
6039
+	icapReadReply(fd, icap);
6040
+}
6041
+
6042
+
6043
+static void
6044
+icapSendRespModDone(int fd, char *bufnotused, size_t size, int errflag,
6045
+    void *data)
6046
+{
6047
+    IcapStateData *icap = data;
6048
+    ErrorState *err;
6049
+
6050
+    icap->flags.write_pending = 0;
6051
+    debug(81, 5) ("icapSendRespModDone: FD %d: size %d: errflag %d.\n",
6052
+	fd, size, errflag);
6053
+    if (size > 0) {
6054
+	fd_bytes(fd, size, FD_WRITE);
6055
+	kb_incr(&statCounter.icap.all.kbytes_out, size);
6056
+    }
6057
+    if (errflag == COMM_ERR_CLOSING)
6058
+	return;
6059
+    if (errflag) {
6060
+	err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
6061
+	err->xerrno = errno;
6062
+	if (cbdataValid(icap))
6063
+	    err->request = requestLink(icap->request);
6064
+	storeEntryReset(icap->respmod.entry);
6065
+	errorAppendEntry(icap->respmod.entry, err);
6066
+	comm_close(fd);
6067
+	return;
6068
+    }
6069
+    if (EBIT_TEST(icap->respmod.entry->flags, ENTRY_ABORTED)) {
6070
+	debug(81, 3) ("icapSendRespModDone: Entry Aborded\n");
6071
+	comm_close(fd);
6072
+	return;
6073
+    }
6074
+    if (icap->flags.send_zero_chunk) {
6075
+	debug(81,
6076
+	    3) ("icapSendRespModDone: I'm supposed to send zero chunk now\n");
6077
+	icap->flags.send_zero_chunk = 0;
6078
+	icapSendRespMod(icap, NULL, 0, 1);
6079
+	return;
6080
+    }
6081
+    if (icap->flags.wait_for_preview_reply || icap->flags.wait_for_reply) {
6082
+	/* Schedule reading the ICAP response */
6083
+	debug(81,
6084
+	    3)
6085
+	    ("icapSendRespModDone: FD %d: commSetSelect on read icapRespModReadReply.\n",
6086
+	    fd);
6087
+	commSetSelect(fd, COMM_SELECT_READ, icapRespModReadReply, icap, 0);
6088
+#if 1
6089
+	commSetTimeout(fd, Config.Timeout.read, icapReadTimeout, icap);
6090
+	commSetDefer(fd, fwdCheckDeferRead, icap->respmod.entry);
6091
+#else
6092
+	if (icap->flags.wait_for_preview_reply || icap->flags.http_server_eof) {
6093
+	    /*
6094
+	     * Set the read timeout only after all data has been sent
6095
+	     * or we are waiting for a preview response
6096
+	     * If the ICAP server does not return any data till all data
6097
+	     * has been sent, we are likely to hit the timeout for large
6098
+	     * HTTP bodies
6099
+	     */
6100
+	    commSetTimeout(fd, Config.Timeout.read, icapReadTimeout, icap);
6101
+	}
6102
+#endif
6103
+    }
6104
+}
6105
+
6106
+void
6107
+icapConnectOver(int fd, int status, void *data)
6108
+{
6109
+    ErrorState *err;
6110
+    IcapStateData *icap = data;
6111
+    debug(81, 3) ("icapConnectOver: FD %d, status=%d\n", fd, status);
6112
+    icap->flags.connect_pending = 0;
6113
+    if (status < 0) {
6114
+	err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
6115
+	err->xerrno = errno;
6116
+	err->request = requestLink(icap->request);
6117
+	errorAppendEntry(icap->respmod.entry, err);
6118
+	comm_close(fd);
6119
+	debug(81, 3) ("icapConnectOver: status < 0, unreachable=1\n");
6120
+	icapOptSetUnreachable(icap->current_service);
6121
+	return;
6122
+    }
6123
+    fd_table[fd].pconn.uses++;
6124
+    fd_table[fd].pconn.type = 2;
6125
+    commSetSelect(fd, COMM_SELECT_READ, icapRespModReadReply, icap, 0);
6126
+}
6127
+
6128
+
6129
+
6130
+IcapStateData *
6131
+icapRespModStart(icap_service_t type, request_t * request, StoreEntry * entry,
6132
+    http_state_flags http_flags)
6133
+{
6134
+    IcapStateData *icap = NULL;
6135
+    CNCB *theCallback = NULL;
6136
+    icap_service *service = NULL;
6137
+
6138
+    debug(81, 3) ("icapRespModStart: type=%d\n", (int) type);
6139
+    assert(type >= 0 && type < ICAP_SERVICE_MAX);
6140
+
6141
+    service = icapService(type, request);
6142
+    if (!service) {
6143
+	debug(81, 3) ("icapRespModStart: no service found\n");
6144
+	return NULL;		/* no service found */
6145
+    }
6146
+    if (service->unreachable) {
6147
+	if (service->bypass) {
6148
+	    debug(81,
6149
+		5)
6150
+		("icapRespModStart: BYPASS because service unreachable: %s\n",
6151
+		service->uri);
6152
+	    return NULL;
6153
+	} else {
6154
+	    debug(81,
6155
+		5)
6156
+		("icapRespModStart: ERROR  because service unreachable: %s\n",
6157
+		service->uri);
6158
+	    return (IcapStateData *) - 1;
6159
+	}
6160
+    }
6161
+    switch (type) {
6162
+	/* TODO: When we support more than ICAP_SERVICE_RESPMOD_PRECACHE, we needs to change
6163
+	 * this switch, because callbacks isn't keep */
6164
+    case ICAP_SERVICE_RESPMOD_PRECACHE:
6165
+	theCallback = icapConnectOver;
6166
+	break;
6167
+    default:
6168
+	fatalf("icapRespModStart: unsupported service type '%s'\n",
6169
+	    icap_service_type_str[type]);
6170
+	break;
6171
+    }
6172
+
6173
+    icap = icapAllocate();
6174
+    if (!icap) {
6175
+	debug(81, 3) ("icapRespModStart: icapAllocate() failed\n");
6176
+	return NULL;
6177
+    }
6178
+    icap->request = requestLink(request);
6179
+    icap->respmod.entry = entry;
6180
+    if (entry)
6181
+	storeLockObject(entry);
6182
+    icap->http_flags = http_flags;
6183
+    memBufDefInit(&icap->respmod.buffer);
6184
+    memBufDefInit(&icap->chunk_buf);
6185
+
6186
+    icap->current_service = service;
6187
+    icap->preview_size = service->preview;
6188
+
6189
+    /* 
6190
+     * Don't create socket to the icap server now, but only for the first
6191
+     * packet receive from the http server. This will resolve all timeout
6192
+     * between the web server and icap server.
6193
+     */
6194
+    debug(81, 3) ("icapRespModStart: setting connect_requested to 0\n");
6195
+    icap->flags.connect_requested = 0;
6196
+
6197
+    /*
6198
+     * make a copy the HTTP response that we send to the ICAP server in
6199
+     * case it turns out to be a 204
6200
+     */
6201
+#ifdef SUPPORT_ICAP_204
6202
+    icap->flags.copy_response = 1;
6203
+#elif ICAP_PREVIEW
6204
+    if (preview_size < 0 || !Config.icapcfg.preview_enable)
6205
+	icap->flags.copy_response = 0;
6206
+    else
6207
+	icap->flags.copy_response = 1;
6208
+#else
6209
+    icap->flags.copy_response = 0;
6210
+#endif
6211
+
6212
+    statCounter.icap.all.requests++;
6213
+    debug(81, 3) ("icapRespModStart: returning %p\n", icap);
6214
+    return icap;
6215
+}
6216
+
6217
+static int
6218
+icapHttpReplyHdrState(IcapStateData * icap)
6219
+{
6220
+    assert(icap);
6221
+    if (NULL == icap->httpState)
6222
+	return 0;
6223
+    return icap->httpState->reply_hdr_state;
6224
+}
6225
+
6226
+static void
6227
+icapProcessHttpReplyHeader(IcapStateData * icap, const char *buf, int size)
6228
+{
6229
+    if (NULL == icap->httpState) {
6230
+	icap->httpState = cbdataAlloc(HttpStateData);
6231
+	icap->httpState->request = requestLink(icap->request);
6232
+	icap->httpState->orig_request = requestLink(icap->request);
6233
+	icap->httpState->entry = icap->respmod.entry;
6234
+	storeLockObject(icap->httpState->entry);	/* lock it */
6235
+    }
6236
+    httpProcessReplyHeader(icap->httpState, buf, size);
6237
+    if (2 == icap->httpState->reply_hdr_state)
6238
+	EBIT_CLR(icap->httpState->entry->flags, ENTRY_FWD_HDR_WAIT);
6239
+}
6240
+
6241
+/*
6242
+ * icapRespModKeepAliveOrClose
6243
+ *
6244
+ * Called when we are done reading from the ICAP server.
6245
+ * Either close the connection or keep it open for a future
6246
+ * transaction.
6247
+ */
6248
+static void
6249
+icapRespModKeepAliveOrClose(IcapStateData * icap)
6250
+{
6251
+    int fd = icap->icap_fd;
6252
+    if (fd < 0)
6253
+	return;
6254
+    if (!icap->flags.keep_alive) {
6255
+	debug(81, 3) ("%s:%d keep_alive not set, closing\n", __FILE__,
6256
+	    __LINE__);
6257
+	comm_close(fd);
6258
+	return;
6259
+    }
6260
+    debug(81, 3) ("%s:%d FD %d looks good, keeping alive\n", __FILE__, __LINE__,
6261
+	fd);
6262
+    commSetDefer(fd, NULL, NULL);
6263
+    commSetTimeout(fd, -1, NULL, NULL);
6264
+    commSetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0);
6265
+    comm_remove_close_handler(fd, icapStateFree, icap);
6266
+    pconnPush(fd, icap->current_service->hostname, icap->current_service->port);
6267
+    icap->icap_fd = -1;
6268
+    icapStateFree(-1, icap);
6269
+}
6270
+
6271
+
6272
+
6273
+/*
6274
+ * copied from httpPconnTransferDone
6275
+ *
6276
+ */
6277
+static int
6278
+icapPconnTransferDone(int fd, IcapStateData * icap)
6279
+{
6280
+    debug(81, 3) ("icapPconnTransferDone: FD %d\n", fd);
6281
+    /*
6282
+     * Be careful with 204 responses.  Normally we are done when we
6283
+     * see the zero-end chunk, but that won't happen for 204s, so we
6284
+     * use an EOF indicator on the HTTP side instead.
6285
+     */
6286
+    if (icap->flags.no_content && icap->flags.http_server_eof) {
6287
+	debug(81, 5) ("icapPconnTransferDone: no content, ret 1\n");
6288
+	return 1;
6289
+    }
6290
+    if (icapHttpReplyHdrState(icap) != 2) {
6291
+	debug(81,
6292
+	    5) ("icapPconnTransferDone: didn't see end of HTTP hdrs, ret 0\n");
6293
+	return 0;
6294
+    }
6295
+    if (icap->enc.null_body > -1) {
6296
+	debug(81, 5) ("icapPconnTransferDone: no message body, ret 1\n");
6297
+	return 1;
6298
+    }
6299
+    if (icap->chunk_size == -2) {	//AI: was != -2 ; and change content with bottom
6300
+	/* zero end chunk reached */
6301
+	debug(81, 5) ("icapPconnTransferDone: got zero end chunk\n");
6302
+	return 1;
6303
+    }
6304
+    debug(81, 5) ("icapPconnTransferDone: didnt get zero end chunk yet\n");	//AI: change with second top condition
6305
+
6306
+    return 0;
6307
+}
6308
+
6309
+static int
6310
+icapExpectedHttpReplyHdrSize(IcapStateData * icap)
6311
+{
6312
+    if (icap->enc.res_body > -1 && icap->enc.res_hdr > -1)
6313
+	return (icap->enc.res_body - icap->enc.res_hdr);
6314
+    if (icap->enc.null_body > -1 && icap->enc.res_hdr > -1)
6315
+	return icap->enc.null_body - icap->enc.res_hdr;
6316
+    /*The case we did not get res_hdr ..... */
6317
+    if (icap->enc.res_body > -1)
6318
+	return icap->enc.res_body;
6319
+    if (icap->enc.null_body > -1)
6320
+	return icap->enc.null_body;
6321
+    return -1;
6322
+}
6323
+
6324
+/*
6325
+ * copied from httpReadReply()
6326
+ *
6327
+ * by the time this is called, the ICAP headers have already
6328
+ * been read.
6329
+ */
6330
+void
6331
+icapReadReply(int fd, void *data)
6332
+{
6333
+    IcapStateData *icap = data;
6334
+    StoreEntry *entry = icap->respmod.entry;
6335
+    const request_t *request = icap->request;
6336
+    int len;
6337
+    debug(81, 5) ("icapReadReply: FD %d: icap %p.\n", fd, data);
6338
+    if (icap->flags.no_content && !icap->flags.http_server_eof) {	//AI
6339
+
6340
+	return;
6341
+    }
6342
+    if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
6343
+	comm_close(fd);
6344
+	return;
6345
+    }
6346
+    errno = 0;
6347
+    statCounter.syscalls.sock.reads++;
6348
+    len = memBufRead(fd, &icap->chunk_buf);
6349
+    debug(81, 5) ("icapReadReply: FD %d: len %d.\n", fd, len);
6350
+    if (len > 0) {
6351
+	fd_bytes(fd, len, FD_READ);
6352
+	kb_incr(&statCounter.icap.all.kbytes_in, len);
6353
+	commSetTimeout(fd, Config.Timeout.read, icapReadTimeout, icap);
6354
+	if (icap->chunk_buf.size < icap->chunk_buf.capacity) {
6355
+	    *(icap->chunk_buf.buf + icap->chunk_buf.size) = '\0';
6356
+	    debug(81, 9) ("{%s}\n", icap->chunk_buf.buf);
6357
+	}
6358
+    }
6359
+    if (len <= 0) {
6360
+	debug(81, 2) ("icapReadReply: FD %d: read failure: %s.\n",
6361
+	    fd, xstrerror());
6362
+	if (ignoreErrno(errno)) {
6363
+	    debug(81, 2) ("icapReadReply: FD %d: ignored errno\n", fd);
6364
+	    commSetSelect(fd, COMM_SELECT_READ, icapReadReply, icap, 0);
6365
+	} else if (entry->mem_obj->inmem_hi == 0) {
6366
+	    ErrorState *err;
6367
+	    debug(81, 2) ("icapReadReply: FD %d: generating error page\n", fd);
6368
+	    err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
6369
+	    err->request = requestLink((request_t *) request);
6370
+	    err->xerrno = errno;
6371
+	    errorAppendEntry(entry, err);
6372
+	    comm_close(fd);
6373
+	} else {
6374
+	    debug(81, 2) ("icapReadReply: FD %d: just calling comm_close()\n",
6375
+		fd);
6376
+	    comm_close(fd);
6377
+	}
6378
+	return;
6379
+    }
6380
+    if (icapReadReply2(icap) < 0)
6381
+	comm_close(fd);
6382
+}
6383
+
6384
+static int
6385
+icapReadReply2(IcapStateData * icap)
6386
+{
6387
+    StoreEntry *entry = icap->respmod.entry;
6388
+    const request_t *request = icap->request;
6389
+    debug(81, 3) ("icapReadReply2\n");
6390
+    if (icap->chunk_buf.size == 0 && entry->mem_obj->inmem_hi == 0) {
6391
+	ErrorState *err;
6392
+	err = errorCon(ERR_ZERO_SIZE_OBJECT, HTTP_SERVICE_UNAVAILABLE);
6393
+	err->xerrno = errno;
6394
+	err->request = requestLink((request_t *) request);
6395
+	errorAppendEntry(entry, err);
6396
+	icap->flags.http_server_eof = 1;
6397
+	return -1;
6398
+    }
6399
+    if (icap->chunk_buf.size == 0) {
6400
+	/* Retrieval done. */
6401
+	if (icapHttpReplyHdrState(icap) < 2)
6402
+	    icapProcessHttpReplyHeader(icap, icap->chunk_buf.buf,
6403
+		icap->chunk_buf.size);
6404
+	icap->flags.http_server_eof = 1;
6405
+	icapReadReply3(icap);
6406
+	return 0;
6407
+    }
6408
+    if (icapHttpReplyHdrState(icap) == 0) {
6409
+	int expect = icapExpectedHttpReplyHdrSize(icap);
6410
+	int so_far = icap->http_header_bytes_read_so_far;
6411
+	int needed = expect - so_far;
6412
+	debug(81, 3) ("expect=%d\n", expect);
6413
+	debug(81, 3) ("so_far=%d\n", so_far);
6414
+	debug(81, 3) ("needed=%d\n", needed);
6415
+	assert(needed < 0 || needed >= 0);
6416
+	if (0 > expect) {
6417
+	    icapProcessHttpReplyHeader(icap,
6418
+		icap->chunk_buf.buf, icap->chunk_buf.size);
6419
+	} else if (0 == expect) {
6420
+	    /*
6421
+	     * this icap reply doesn't give us new HTTP headers
6422
+	     * so we must copy them from our copy
6423
+	     */
6424
+	    debug(81, 1) ("WARNING: untested code at %s:%d\n", __FILE__,
6425
+		__LINE__);
6426
+	    if (icap->respmod.req_hdr_copy.size) {	/*For HTTP 0.9 we do not have headers */
6427
+		storeAppend(entry,
6428
+		    icap->respmod.req_hdr_copy.buf,
6429
+		    icap->respmod.req_hdr_copy.size);
6430
+	    }
6431
+	    icapProcessHttpReplyHeader(icap, icap->chunk_buf.buf,
6432
+		icap->chunk_buf.size);
6433
+	    assert(icapHttpReplyHdrState(icap) == 2);
6434
+	    icap->chunk_size = 0;	/*we are ready to read chunks of data now.... */
6435
+	} else if (needed) {
6436
+	    icapProcessHttpReplyHeader(icap,
6437
+		icap->chunk_buf.buf, icap->chunk_buf.size);
6438
+	    if (icap->chunk_buf.size >= needed) {
6439
+		storeAppend(entry, icap->chunk_buf.buf, needed);
6440
+		so_far += needed;
6441
+		xmemmove(icap->chunk_buf.buf,
6442
+		    icap->chunk_buf.buf + needed,
6443
+		    icap->chunk_buf.size - needed);
6444
+		icap->chunk_buf.size -= needed;
6445
+		assert(icapHttpReplyHdrState(icap) == 2);
6446
+		icap->chunk_size = 0;
6447
+	    } else {
6448
+		/*
6449
+		 * We don't have the full HTTP reply headers yet, so keep
6450
+		 * the partial reply buffered in 'chunk_buf' and wait
6451
+		 * for more.
6452
+		 */
6453
+		debug(81, 3) ("We don't have full Http headers.Schedule a new read\n");
6454
+		commSetSelect(icap->icap_fd, COMM_SELECT_READ, icapReadReply, icap, 0);
6455
+	    }
6456
+	}
6457
+	icap->http_header_bytes_read_so_far = so_far;
6458
+    }
6459
+    debug(81, 3) ("%s:%d: icap->chunk_buf.size=%d\n", __FILE__, __LINE__,
6460
+	(int) icap->chunk_buf.size);
6461
+    debug(81, 3) ("%s:%d: flags.no_content=%d\n", __FILE__, __LINE__,
6462
+	icap->flags.no_content);
6463
+    if (icap->flags.no_content) {
6464
+	/* data from http.c is not chunked */
6465
+	if (!EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
6466
+	    debug(81, 3) ("copying %d bytes from chunk_buf to entry\n",
6467
+		icap->chunk_buf.size);
6468
+	    storeAppend(entry, icap->chunk_buf.buf, icap->chunk_buf.size);
6469
+	    icap->chunk_buf.size = 0;
6470
+	}
6471
+    } else if (2 == icapHttpReplyHdrState(icap)) {
6472
+	if (icap->chunk_buf.size)
6473
+	    icapParseChunkedBody(icap, (STRCB *) storeAppend, entry);
6474
+    }
6475
+    icapReadReply3(icap);
6476
+    return 0;
6477
+}
6478
+
6479
+static void
6480
+icapReadReply3(IcapStateData * icap)
6481
+{
6482
+    StoreEntry *entry = icap->respmod.entry;
6483
+    int fd = icap->icap_fd;
6484
+    debug(81, 3) ("icapReadReply3\n");
6485
+    if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
6486
+	debug(81, 3) ("icapReadReply3: Entry Aborded\n");
6487
+	comm_close(fd);
6488
+    } else if (icapPconnTransferDone(fd, icap)) {
6489
+	storeComplete(entry);
6490
+	icapRespModKeepAliveOrClose(icap);
6491
+    } else if (!icap->flags.no_content) {
6492
+	/* Wait for EOF condition */
6493
+	commSetSelect(fd, COMM_SELECT_READ, icapReadReply, icap, 0);
6494
+	debug(81,
6495
+	    3)
6496
+	    ("icapReadReply3: Going to read mode data throught icapReadReply\n");
6497
+    } else {
6498
+	debug(81, 3) ("icapReadReply3: Nothing\n");
6499
+    }
6500
+}
6501
Index: src/main.c
6502
===================================================================
6503
RCS file: /cvsroot/squid/squid/src/main.c,v
6504
retrieving revision 1.28.6.25
6505
retrieving revision 1.28.6.8.2.11
6506
diff -p -u -b -r1.28.6.25 -r1.28.6.8.2.11
6507
--- src/main.c	28 Jun 2005 02:16:51 -0000	1.28.6.25
6508
+++ src/main.c	12 Sep 2005 18:34:41 -0000	1.28.6.8.2.11
6509
@@ -350,6 +350,9 @@ mainReconfigure(void)
6510
 #else
6511
     idnsShutdown();
6512
 #endif
6513
+#ifdef HS_FEAT_ICAP
6514
+    icapClose();
6515
+#endif
6516
     redirectShutdown();
6517
     authenticateShutdown();
6518
     externalAclShutdown();
6519
@@ -378,6 +381,9 @@ mainReconfigure(void)
6520
     idnsInit();
6521
 #endif
6522
     redirectInit();
6523
+#ifdef HS_FEAT_ICAP
6524
+    icapInit();
6525
+#endif
6526
     authenticateInit(&Config.authConfig);
6527
     externalAclInit();
6528
 #if USE_WCCP
6529
@@ -507,6 +513,9 @@ mainInitialize(void)
6530
     idnsInit();
6531
 #endif
6532
     redirectInit();
6533
+#ifdef HS_FEAT_ICAP
6534
+    icapInit();
6535
+#endif
6536
     authenticateInit(&Config.authConfig);
6537
     externalAclInit();
6538
     useragentOpenLog();
6539
Index: src/mem.c
6540
===================================================================
6541
RCS file: /cvsroot/squid/squid/src/mem.c,v
6542
retrieving revision 1.13
6543
retrieving revision 1.13.28.2
6544
diff -p -u -b -r1.13 -r1.13.28.2
6545
--- src/mem.c	7 Sep 2001 23:55:49 -0000	1.13
6546
+++ src/mem.c	27 Jun 2003 01:15:18 -0000	1.13.28.2
6547
@@ -243,6 +243,13 @@ memInit(void)
6548
     memDataInit(MEM_CLIENT_REQ_BUF, "clientRequestBuffer", CLIENT_REQ_BUF_SZ, 0);
6549
     memDataInit(MEM_SWAP_LOG_DATA, "storeSwapLogData", sizeof(storeSwapLogData), 0);
6550
 
6551
+#ifdef HS_FEAT_ICAP
6552
+    memDataInit(MEM_ICAP_OPT_DATA, "IcapOptData", sizeof(IcapOptData), 0);
6553
+    memDataInit(MEM_ICAP_SERVICE_LIST, "icap_service_list", sizeof(icap_service_list), 0);
6554
+    memDataInit(MEM_ICAP_CLASS, "icap_class", sizeof(icap_class), 0);
6555
+    memDataInit(MEM_ICAP_ACCESS, "icap_access", sizeof(icap_access), 0);
6556
+#endif
6557
+
6558
     /* init string pools */
6559
     for (i = 0; i < mem_str_pool_count; i++) {
6560
 	StrPools[i].pool = memPoolCreate(StrPoolsAttrs[i].name, StrPoolsAttrs[i].obj_size);
6561
Index: src/mk-string-arrays.pl
6562
===================================================================
6563
RCS file: /cvsroot/squid/squid/src/mk-string-arrays.pl,v
6564
retrieving revision 1.2
6565
retrieving revision 1.2.140.1
6566
diff -p -u -b -r1.2 -r1.2.140.1
6567
--- src/mk-string-arrays.pl	23 Oct 2000 15:04:21 -0000	1.2
6568
+++ src/mk-string-arrays.pl	4 Apr 2003 16:55:44 -0000	1.2.140.1
6569
@@ -16,6 +16,7 @@ $pat{'err_type'} = "err_type_str";
6570
 $pat{'icp_opcode'} = "icp_opcode_str";
6571
 $pat{'swap_log_op'} = "swap_log_op_str";
6572
 $pat{'lookup_t'} = "lookup_t_str";
6573
+$pat{'icap_service_t'} = "icap_service_type_str";
6574
 
6575
 $state = 0;	# start state
6576
 while (<>) {
6577
Index: src/pconn.c
6578
===================================================================
6579
RCS file: /cvsroot/squid/squid/src/pconn.c,v
6580
retrieving revision 1.6.38.2
6581
retrieving revision 1.6.60.2
6582
diff -p -u -b -r1.6.38.2 -r1.6.60.2
6583
--- src/pconn.c	16 Dec 2003 03:13:59 -0000	1.6.38.2
6584
+++ src/pconn.c	23 Nov 2005 20:33:07 -0000	1.6.60.2
6585
@@ -46,6 +46,9 @@ struct _pconn {
6586
 #define PCONN_HIST_SZ (1<<16)
6587
 int client_pconn_hist[PCONN_HIST_SZ];
6588
 int server_pconn_hist[PCONN_HIST_SZ];
6589
+#ifdef HS_FEAT_ICAP
6590
+int icap_server_pconn_hist[PCONN_HIST_SZ];
6591
+#endif
6592
 
6593
 static PF pconnRead;
6594
 static PF pconnTimeout;
6595
@@ -159,6 +162,20 @@ pconnHistDump(StoreEntry * e)
6596
 	    continue;
6597
 	storeAppendPrintf(e, "\t%4d  %9d\n", i, server_pconn_hist[i]);
6598
     }
6599
+#ifdef HS_FEAT_ICAP
6600
+    storeAppendPrintf(e,
6601
+	"\n"
6602
+	"ICAP-server persistent connection counts:\n"
6603
+	"\n"
6604
+	"\treq/\n"
6605
+	"\tconn      count\n"
6606
+	"\t----  ---------\n");
6607
+    for (i = 0; i < PCONN_HIST_SZ; i++) {
6608
+	if (icap_server_pconn_hist[i] == 0)
6609
+	    continue;
6610
+	storeAppendPrintf(e, "\t%4d  %9d\n", i, icap_server_pconn_hist[i]);
6611
+    }
6612
+#endif
6613
 }
6614
 
6615
 /* ========== PUBLIC FUNCTIONS ============================================ */
6616
@@ -173,6 +190,9 @@ pconnInit(void)
6617
     for (i = 0; i < PCONN_HIST_SZ; i++) {
6618
 	client_pconn_hist[i] = 0;
6619
 	server_pconn_hist[i] = 0;
6620
+#ifdef HS_FEAT_ICAP
6621
+	icap_server_pconn_hist[i] = 0;
6622
+#endif
6623
     }
6624
     pconn_data_pool = memPoolCreate("pconn_data", sizeof(struct _pconn));
6625
     pconn_fds_pool = memPoolCreate("pconn_fds", PCONN_FDS_SZ * sizeof(int));
6626
@@ -248,11 +268,15 @@ pconnHistCount(int what, int i)
6627
 {
6628
     if (i >= PCONN_HIST_SZ)
6629
 	i = PCONN_HIST_SZ - 1;
6630
-    /* what == 0 for client, 1 for server */
6631
+    /* what == 0 for client, 1 for server, 2 for ICAP server */
6632
     if (what == 0)
6633
 	client_pconn_hist[i]++;
6634
     else if (what == 1)
6635
 	server_pconn_hist[i]++;
6636
+#ifdef HS_FEAT_ICAP
6637
+    else if (what == 2)
6638
+	icap_server_pconn_hist[i]++;
6639
+#endif
6640
     else
6641
 	assert(0);
6642
 }
6643
Index: src/protos.h
6644
===================================================================
6645
RCS file: /cvsroot/squid/squid/src/protos.h,v
6646
retrieving revision 1.41.6.34
6647
retrieving revision 1.41.6.13.2.39
6648
diff -p -u -b -r1.41.6.34 -r1.41.6.13.2.39
6649
--- src/protos.h	26 Feb 2006 03:13:57 -0000	1.41.6.34
6650
+++ src/protos.h	16 May 2006 17:56:59 -0000	1.41.6.13.2.39
6651
@@ -292,6 +292,8 @@ extern void whoisStart(FwdState *);
6652
 /* http.c */
6653
 extern int httpCachable(method_t);
6654
 extern void httpStart(FwdState *);
6655
+extern void httpParseReplyHeaders(const char *, http_reply *);
6656
+extern void httpProcessReplyHeader(HttpStateData *, const char *, int);
6657
 extern int httpBuildRequestPrefix(request_t * request,
6658
     request_t * orig_request,
6659
     StoreEntry * entry,
6660
@@ -614,6 +616,7 @@ extern void memBufVPrintf(MemBuf * mb, c
6661
 extern FREE *memBufFreeFunc(MemBuf * mb);
6662
 /* puts report on MemBuf _module_ usage into mb */
6663
 extern void memBufReport(MemBuf * mb);
6664
+extern int memBufRead(int fd, MemBuf * mb);
6665
 
6666
 extern char *mime_get_header(const char *mime, const char *header);
6667
 extern char *mime_get_header_field(const char *mime, const char *name, const char *prefix);
6668
@@ -1341,4 +1344,53 @@ extern void externalAclShutdown(void);
6669
 extern int externalAclRequiresAuth(void *acl_data);
6670
 extern char *strtokFile(void);
6671
 
6672
+#ifdef HS_FEAT_ICAP
6673
+/*
6674
+ * icap_common.c
6675
+ */
6676
+void icapInit(void);
6677
+void icapClose(void);
6678
+void icapParseEncapsulated(IcapStateData *, const char *, const char *);
6679
+icap_service *icapService(icap_service_t, request_t *);
6680
+int icapConnect(IcapStateData *, CNCB *);
6681
+IcapStateData *icapAllocate(void);
6682
+PF icapStateFree;
6683
+PF icapConnectTimeout;
6684
+PF icapReadTimeout;
6685
+icap_service_t icapServiceToType(const char *);
6686
+const char *icapServiceToStr(const icap_service_t);
6687
+int icapCheckAcl(clientHttpRequest *);
6688
+size_t icapLineLength(const char *, int);
6689
+int icapReadHeader(int, IcapStateData *, int *);
6690
+int icapFindHeader(const char *, const char *, const char **, const char **);
6691
+int icapParseKeepAlive(const IcapStateData *, const char *, const char *);
6692
+void icapSetKeepAlive(IcapStateData * icap, const char *hdrs);
6693
+size_t icapParseChunkedBody(IcapStateData *, STRCB *, void *);
6694
+void icapAddAuthUserHeader(MemBuf *, auth_user_request_t *);
6695
+int icapParseStatusLine(const char *, int, int *, int *, const char **);
6696
+
6697
+/*
6698
+ * icap_respmod.c
6699
+ */
6700
+IcapStateData *icapRespModStart(icap_service_t, request_t *, StoreEntry *, http_state_flags);
6701
+void icapSendRespMod(IcapStateData *, char *, int, int);
6702
+CNCB icapConnectOver;
6703
+
6704
+/*
6705
+ * icap_reqmod.c
6706
+ */
6707
+IcapStateData *icapReqModStart(icap_service*, const char *, request_t *, int, struct timeval, struct in_addr, void *);
6708
+
6709
+/* icap_opt.c */
6710
+void icapOptInit(void);
6711
+void icapOptShutdown(void);
6712
+void icapOptSetUnreachable(icap_service * s);
6713
+
6714
+/* X-Server-IP support */
6715
+void icapAddOriginIP(MemBuf *, const char *);
6716
+
6717
+/* for debugging purposes only */
6718
+void dump_icap_config(IcapConfig * cfg);
6719
+#endif
6720
+
6721
 #endif /* SQUID_PROTOS_H */
6722
Index: src/squid.h
6723
===================================================================
6724
RCS file: /cvsroot/squid/squid/src/squid.h,v
6725
retrieving revision 1.13.6.9
6726
retrieving revision 1.13.6.6.2.12
6727
diff -p -u -b -r1.13.6.9 -r1.13.6.6.2.12
6728
--- src/squid.h	11 Mar 2006 03:16:31 -0000	1.13.6.9
6729
+++ src/squid.h	16 May 2006 17:56:59 -0000	1.13.6.6.2.12
6730
@@ -38,6 +38,14 @@
6731
 #include "config.h"
6732
 
6733
 /*
6734
+ * experimental defines for ICAP
6735
+ */
6736
+#ifdef HS_FEAT_ICAP
6737
+#define ICAP_PREVIEW 1
6738
+#define SUPPORT_ICAP_204 0
6739
+#endif
6740
+
6741
+/*
6742
  * On some systems, FD_SETSIZE is set to something lower than the
6743
  * actual number of files which can be opened.  IRIX is one case,
6744
  * NetBSD is another.  So here we increase FD_SETSIZE to our
6745
Index: src/stat.c
6746
===================================================================
6747
RCS file: /cvsroot/squid/squid/src/stat.c,v
6748
retrieving revision 1.13.6.14
6749
retrieving revision 1.13.6.7.2.7
6750
diff -p -u -b -r1.13.6.14 -r1.13.6.7.2.7
6751
--- src/stat.c	30 Mar 2005 02:17:46 -0000	1.13.6.14
6752
+++ src/stat.c	23 Nov 2005 20:33:07 -0000	1.13.6.7.2.7
6753
@@ -775,6 +775,17 @@ statAvgDump(StoreEntry * sentry, int min
6754
     storeAppendPrintf(sentry, "server.other.kbytes_out = %f/sec\n",
6755
 	XAVG(server.other.kbytes_out.kb));
6756
 
6757
+#ifdef HS_FEAT_ICAP
6758
+    storeAppendPrintf(sentry, "icap.all.requests = %f/sec\n",
6759
+	XAVG(icap.all.requests));
6760
+    storeAppendPrintf(sentry, "icap.all.errors = %f/sec\n",
6761
+	XAVG(icap.all.errors));
6762
+    storeAppendPrintf(sentry, "icap.all.kbytes_in = %f/sec\n",
6763
+	XAVG(icap.all.kbytes_in.kb));
6764
+    storeAppendPrintf(sentry, "icap.all.kbytes_out = %f/sec\n",
6765
+	XAVG(icap.all.kbytes_out.kb));
6766
+#endif
6767
+
6768
     storeAppendPrintf(sentry, "icp.pkts_sent = %f/sec\n",
6769
 	XAVG(icp.pkts_sent));
6770
     storeAppendPrintf(sentry, "icp.pkts_recv = %f/sec\n",
6771
@@ -1160,6 +1171,17 @@ statCountersDump(StoreEntry * sentry)
6772
     storeAppendPrintf(sentry, "server.other.kbytes_out = %d\n",
6773
 	(int) f->server.other.kbytes_out.kb);
6774
 
6775
+#if HS_FEAT_ICAP
6776
+    storeAppendPrintf(sentry, "icap.all.requests = %d\n",
6777
+	(int) f->icap.all.requests);
6778
+    storeAppendPrintf(sentry, "icap.all.errors = %d\n",
6779
+	(int) f->icap.all.errors);
6780
+    storeAppendPrintf(sentry, "icap.all.kbytes_in = %d\n",
6781
+	(int) f->icap.all.kbytes_in.kb);
6782
+    storeAppendPrintf(sentry, "icap.all.kbytes_out = %d\n",
6783
+	(int) f->icap.all.kbytes_out.kb);
6784
+#endif
6785
+
6786
     storeAppendPrintf(sentry, "icp.pkts_sent = %d\n",
6787
 	f->icp.pkts_sent);
6788
     storeAppendPrintf(sentry, "icp.pkts_recv = %d\n",
6789
@@ -1459,8 +1481,6 @@ statClientRequests(StoreEntry * s)
6790
 	    storeAppendPrintf(s, "\tme: %s:%d\n",
6791
 		inet_ntoa(conn->me.sin_addr),
6792
 		ntohs(conn->me.sin_port));
6793
-	    storeAppendPrintf(s, "\tnrequests: %d\n",
6794
-		conn->nrequests);
6795
 	    storeAppendPrintf(s, "\tdefer: n %d, until %ld\n",
6796
 		conn->defer.n, (long int) conn->defer.until);
6797
 	}
6798
Index: src/store.c
6799
===================================================================
6800
RCS file: /cvsroot/squid/squid/src/store.c,v
6801
retrieving revision 1.16.6.9
6802
retrieving revision 1.16.6.2.2.8
6803
diff -p -u -b -r1.16.6.9 -r1.16.6.2.2.8
6804
--- src/store.c	2 Sep 2005 02:13:43 -0000	1.16.6.9
6805
+++ src/store.c	12 Sep 2005 18:34:41 -0000	1.16.6.2.2.8
6806
@@ -520,7 +520,16 @@ storeAppend(StoreEntry * e, const char *
6807
     MemObject *mem = e->mem_obj;
6808
     assert(mem != NULL);
6809
     assert(len >= 0);
6810
-    assert(e->store_status == STORE_PENDING);
6811
+    debug(20, 3) ("storeAppend: '%s'\n", storeKeyText(e->hash.key));
6812
+    if (e->store_status != STORE_PENDING) {
6813
+	/*
6814
+	 * if we're not STORE_PENDING, then probably we got aborted
6815
+	 * and there should be NO clients on this entry
6816
+	 */
6817
+	assert(EBIT_TEST(e->flags, ENTRY_ABORTED));
6818
+	assert(e->mem_obj->nclients == 0);
6819
+	return;
6820
+    }
6821
     if (len) {
6822
 	debug(20, 5) ("storeAppend: appending %d bytes for '%s'\n",
6823
 	    len,
6824
Index: src/structs.h
6825
===================================================================
6826
RCS file: /cvsroot/squid/squid/src/structs.h,v
6827
retrieving revision 1.48.2.46
6828
retrieving revision 1.48.2.9.2.50
6829
diff -p -u -b -r1.48.2.46 -r1.48.2.9.2.50
6830
--- src/structs.h	11 Mar 2006 03:16:31 -0000	1.48.2.46
6831
+++ src/structs.h	16 May 2006 17:56:59 -0000	1.48.2.9.2.50
6832
@@ -384,6 +384,23 @@ struct _RemovalPolicySettings {
6833
     wordlist *args;
6834
 };
6835
 
6836
+#if HS_FEAT_ICAP
6837
+struct _IcapConfig {
6838
+    int onoff;
6839
+    int preview_enable;
6840
+    icap_service *service_head;
6841
+    icap_class *class_head;
6842
+    icap_access *access_head;
6843
+    int preview_size;
6844
+    int check_interval;
6845
+    int send_client_ip;
6846
+    int send_server_ip;
6847
+    int send_auth_user;
6848
+    char *auth_scheme;
6849
+};
6850
+
6851
+#endif /* HS_FEAT_ICAP */
6852
+
6853
 struct _SquidConfig {
6854
     struct {
6855
 	squid_off_t maxSize;
6856
@@ -715,6 +732,9 @@ struct _SquidConfig {
6857
     char *store_dir_select_algorithm;
6858
     int sleep_after_fork;	/* microseconds */
6859
     external_acl *externalAclHelperList;
6860
+#ifdef HS_FEAT_ICAP
6861
+    IcapConfig icapcfg;
6862
+#endif
6863
 };
6864
 
6865
 struct _SquidConfig2 {
6866
@@ -788,7 +808,10 @@ struct _fde {
6867
     } flags;
6868
     squid_off_t bytes_read;
6869
     squid_off_t bytes_written;
6870
-    int uses;			/* ie # req's over persistent conn */
6871
+    struct {
6872
+	int uses;
6873
+	int type;
6874
+    } pconn;
6875
     struct _fde_disk {
6876
 	DWCB *wrt_handle;
6877
 	void *wrt_handle_data;
6878
@@ -983,6 +1006,131 @@ struct _http_state_flags {
6879
     unsigned int request_sent:1;
6880
 };
6881
 
6882
+#ifdef HS_FEAT_ICAP
6883
+struct _IcapStateData {
6884
+    request_t *request;
6885
+    http_state_flags http_flags;
6886
+    HttpStateData *httpState;	/* needed to parse HTTP headers only */
6887
+    int icap_fd;
6888
+    int sc;
6889
+    icap_service *current_service;
6890
+    MemBuf icap_hdr;
6891
+    struct {
6892
+	int res_hdr;
6893
+	int res_body;
6894
+	int req_hdr;
6895
+	int req_body;
6896
+	int opt_body;
6897
+	int null_body;
6898
+    } enc;
6899
+    int bytes_to_gobble;
6900
+    int chunk_size;
6901
+    MemBuf chunk_buf;
6902
+    int preview_size;
6903
+    squid_off_t fake_content_length;
6904
+    int http_header_bytes_read_so_far;
6905
+    struct {
6906
+	const char *uri;	/* URI for REQMODs */
6907
+	int client_fd;
6908
+	struct timeval start;	/* for logging */
6909
+	struct in_addr log_addr;	/* for logging */
6910
+	int hdr_state;
6911
+	MemBuf hdr_buf;
6912
+	void *client_cookie;
6913
+	struct {
6914
+	    MemBuf buf;
6915
+	    CBCB *callback;
6916
+	    void *callback_data;
6917
+	    char *callback_buf;
6918
+	    size_t callback_bufsize;
6919
+	    squid_off_t bytes_read;
6920
+	} http_entity;
6921
+    } reqmod;
6922
+    struct {
6923
+	StoreEntry *entry;
6924
+	MemBuf buffer;
6925
+	MemBuf req_hdr_copy;	/* XXX barf */
6926
+	MemBuf resp_copy;	/* XXX barf^max */
6927
+	squid_off_t res_body_sz;
6928
+    } respmod;
6929
+    struct {
6930
+	unsigned int connect_requested:1;
6931
+	unsigned int connect_pending:1;
6932
+	unsigned int write_pending:1;
6933
+	unsigned int keep_alive:1;
6934
+	unsigned int http_server_eof:1;
6935
+	unsigned int send_zero_chunk:1;
6936
+	unsigned int got_reply:1;
6937
+	unsigned int wait_for_reply:1;
6938
+	unsigned int wait_for_preview_reply:1;
6939
+	unsigned int preview_done:1;
6940
+	unsigned int copy_response:1;
6941
+	unsigned int no_content:1;
6942
+	unsigned int reqmod_http_entity_eof:1;
6943
+    } flags;
6944
+};
6945
+
6946
+struct _icap_service {
6947
+    icap_service *next;
6948
+    char *name;			/* name to be used when referencing ths service */
6949
+    char *uri;			/* uri of server/service to use */
6950
+    char *type_name;		/* {req|resp}mod_{pre|post}cache */
6951
+
6952
+    char *hostname;
6953
+    unsigned short int port;
6954
+    char *resource;
6955
+    icap_service_t type;	/* parsed type */
6956
+    icap_method_t method;
6957
+    ushort bypass;		/* flag: bypass allowed */
6958
+    ushort unreachable;		/* flag: set to 1 if options request fails */
6959
+    IcapOptData *opt;		/* temp data needed during opt request */
6960
+    struct {
6961
+	unsigned int allow_204:1;
6962
+	unsigned int need_x_client_ip:1;
6963
+	unsigned int need_x_server_ip:1;
6964
+	unsigned int need_x_authenticated_user:1;
6965
+    } flags;
6966
+    int preview;
6967
+    String istag;
6968
+    String transfer_preview;
6969
+    String transfer_ignore;
6970
+    String transfer_complete;
6971
+    int max_connections;
6972
+    int options_ttl;
6973
+    int keep_alive;
6974
+};
6975
+
6976
+struct _icap_service_list {
6977
+    icap_service_list *next;
6978
+    icap_service *services[16];
6979
+    int nservices;		/* Number of services already used */
6980
+    int last_service_used;	/* Last services used, use to do a round robin */
6981
+};
6982
+
6983
+struct _icap_class {
6984
+    icap_class *next;
6985
+    char *name;
6986
+    wordlist *services;
6987
+    icap_service_list *isl;
6988
+    ushort hidden;		/* for unnamed classes */
6989
+};
6990
+
6991
+struct _icap_access {
6992
+    icap_access *next;
6993
+    char *service_name;
6994
+    icap_class *class;
6995
+    acl_access *access;
6996
+};
6997
+
6998
+struct _IcapOptData {
6999
+    char *buf;
7000
+    off_t offset;
7001
+    size_t size;
7002
+    off_t headlen;
7003
+};
7004
+
7005
+#endif
7006
+
7007
 struct _HttpStateData {
7008
     StoreEntry *entry;
7009
     request_t *request;
7010
@@ -994,10 +1142,14 @@ struct _HttpStateData {
7011
     int fd;
7012
     http_state_flags flags;
7013
     FwdState *fwd;
7014
+#ifdef HS_FEAT_ICAP
7015
+    struct _IcapStateData *icap_writer;
7016
+#endif
7017
     char *body_buf;
7018
     int body_buf_sz;
7019
 };
7020
 
7021
+
7022
 struct _icpUdpData {
7023
     struct sockaddr_in address;
7024
     void *msg;
7025
@@ -1099,6 +1251,7 @@ struct _clientHttpRequest {
7026
 	unsigned int internal:1;
7027
 	unsigned int done_copying:1;
7028
 	unsigned int purging:1;
7029
+	unsigned int did_icap_reqmod:1;
7030
 	unsigned int hit:1;
7031
     } flags;
7032
     struct {
7033
@@ -1107,6 +1260,9 @@ struct _clientHttpRequest {
7034
     } redirect;
7035
     dlink_node active;
7036
     squid_off_t maxBodySize;
7037
+#if HS_FEAT_ICAP
7038
+    IcapStateData *icap_reqmod;
7039
+#endif
7040
 };
7041
 
7042
 struct _ConnStateData {
7043
@@ -1134,7 +1290,6 @@ struct _ConnStateData {
7044
     struct sockaddr_in me;
7045
     struct in_addr log_addr;
7046
     char rfc931[USER_IDENT_SZ];
7047
-    int nrequests;
7048
     struct {
7049
 	int n;
7050
 	time_t until;
7051
@@ -1685,6 +1840,9 @@ struct _request_t {
7052
     char *peer_login;		/* Configured peer login:password */
7053
     time_t lastmod;		/* Used on refreshes */
7054
     const char *vary_headers;	/* Used when varying entities are detected. Changes how the store key is calculated */
7055
+#if HS_FEAT_ICAP
7056
+    icap_class *class;
7057
+#endif
7058
     BODY_HANDLER *body_reader;
7059
     void *body_reader_data;
7060
 };
7061
@@ -1790,7 +1948,11 @@ struct _StatCounters {
7062
 	    kb_t kbytes_in;
7063
 	    kb_t kbytes_out;
7064
 	} all , http, ftp, other;
7065
-    } server;
7066
+    }
7067
+#if HS_FEAT_ICAP
7068
+	icap,
7069
+#endif
7070
+	server;
7071
     struct {
7072
 	int pkts_sent;
7073
 	int queries_sent;
7074
Index: src/typedefs.h
7075
===================================================================
7076
RCS file: /cvsroot/squid/squid/src/typedefs.h,v
7077
retrieving revision 1.25.6.8
7078
retrieving revision 1.25.6.1.6.13
7079
diff -p -u -b -r1.25.6.8 -r1.25.6.1.6.13
7080
--- src/typedefs.h	27 Mar 2005 02:16:17 -0000	1.25.6.8
7081
+++ src/typedefs.h	28 Mar 2005 18:05:08 -0000	1.25.6.1.6.13
7082
@@ -131,6 +131,15 @@ typedef struct _HttpHeaderStat HttpHeade
7083
 typedef struct _HttpBody HttpBody;
7084
 typedef struct _HttpReply HttpReply;
7085
 typedef struct _HttpStateData HttpStateData;
7086
+#ifdef HS_FEAT_ICAP
7087
+typedef struct _IcapStateData IcapStateData;
7088
+typedef struct _IcapConfig IcapConfig;
7089
+typedef struct _icap_service icap_service;
7090
+typedef struct _icap_service_list icap_service_list;
7091
+typedef struct _icap_class icap_class;
7092
+typedef struct _icap_access icap_access;
7093
+typedef struct _IcapOptData IcapOptData;
7094
+#endif
7095
 typedef struct _icpUdpData icpUdpData;
7096
 typedef struct _clientHttpRequest clientHttpRequest;
7097
 typedef struct _ConnStateData ConnStateData;
7098
Index: src/url.c
7099
===================================================================
7100
RCS file: /cvsroot/squid/squid/src/url.c,v
7101
retrieving revision 1.7.6.7
7102
retrieving revision 1.7.6.5.2.3
7103
diff -p -u -b -r1.7.6.7 -r1.7.6.5.2.3
7104
--- src/url.c	11 Mar 2006 03:16:31 -0000	1.7.6.7
7105
+++ src/url.c	16 May 2006 17:56:59 -0000	1.7.6.5.2.3
7106
@@ -103,6 +103,9 @@ const char *ProtocolStr[] =
7107
     "whois",
7108
     "internal",
7109
     "https",
7110
+#ifdef HS_FEAT_ICAP
7111
+    "icap",
7112
+#endif
7113
     "TOTAL"
7114
 };
7115
 
7116
@@ -221,6 +224,10 @@ urlParseProtocol(const char *s)
7117
 	return PROTO_WHOIS;
7118
     if (strcasecmp(s, "internal") == 0)
7119
 	return PROTO_INTERNAL;
7120
+#ifdef HS_FEAT_ICAP
7121
+    if (strcasecmp(s, "icap") == 0)
7122
+	return PROTO_ICAP;
7123
+#endif
7124
     return PROTO_NONE;
7125
 }
7126
 
7127
@@ -244,6 +251,10 @@ urlDefaultPort(protocol_t p)
7128
 	return CACHE_HTTP_PORT;
7129
     case PROTO_WHOIS:
7130
 	return 43;
7131
+#ifdef HS_FEAT_ICAP
7132
+    case PROTO_ICAP:
7133
+	return 1344;
7134
+#endif
7135
     default:
7136
 	return 0;
7137
     }
(-)files/follow_xff-2.5.patch (-411 lines)
Lines 1-411 Link Here
1
! This is a reduced part of the original follow-XFF patchset from
2
! devel.squid-cache.org for use with the FreeBSD squid-2.5 port.
3
Index: src/acl.c
4
--- src/acl.c	13 May 2003 02:14:12 -0000	1.43.2.16
5
+++ src/acl.c	23 Nov 2003 14:20:12 -0000
6
@@ -2001,6 +2001,11 @@
7
     cbdataLock(A);
8
     if (request != NULL) {
9
 	checklist->request = requestLink(request);
10
+#if FOLLOW_X_FORWARDED_FOR
11
+	if (Config.onoff.acl_uses_indirect_client) {
12
+	    checklist->src_addr = request->indirect_client_addr;
13
+	} else
14
+#endif /* FOLLOW_X_FORWARDED_FOR */
15
 	checklist->src_addr = request->client_addr;
16
 	checklist->my_addr = request->my_addr;
17
 	checklist->my_port = request->my_port;
18
Index: src/cf.data.pre
19
--- src/cf.data.pre	7 Nov 2003 03:14:30 -0000	1.49.2.46
20
+++ src/cf.data.pre	23 Nov 2003 14:20:17 -0000
21
@@ -2065,6 +2065,92 @@
22
 NOCOMMENT_END
23
 DOC_END
24
 
25
+NAME: follow_x_forwarded_for
26
+TYPE: acl_access
27
+IFDEF: FOLLOW_X_FORWARDED_FOR
28
+LOC: Config.accessList.followXFF
29
+DEFAULT: none
30
+DEFAULT_IF_NONE: deny all
31
+DOC_START
32
+	Allowing or Denying the X-Forwarded-For header to be followed to
33
+	find the original source of a request.
34
+
35
+	Requests may pass through a chain of several other proxies
36
+	before reaching us.  The X-Forwarded-For header will contain a
37
+	comma-separated list of the IP addresses in the chain, with the
38
+	rightmost address being the most recent.
39
+
40
+	If a request reaches us from a source that is allowed by this
41
+	configuration item, then we consult the X-Forwarded-For header
42
+	to see where that host received the request from.  If the
43
+	X-Forwarded-For header contains multiple addresses, and if
44
+	acl_uses_indirect_client is on, then we continue backtracking
45
+	until we reach an address for which we are not allowed to
46
+	follow the X-Forwarded-For header, or until we reach the first
47
+	address in the list.  (If acl_uses_indirect_client is off, then
48
+	it's impossible to backtrack through more than one level of
49
+	X-Forwarded-For addresses.)
50
+
51
+	The end result of this process is an IP address that we will
52
+	refer to as the indirect client address.  This address may
53
+	be treated as the client address for access control, delay
54
+	pools and logging, depending on the acl_uses_indirect_client,
55
+	delay_pool_uses_indirect_client and log_uses_indirect_client
56
+	options.
57
+
58
+	SECURITY CONSIDERATIONS:
59
+
60
+		Any host for which we follow the X-Forwarded-For header
61
+		can place incorrect information in the header, and Squid
62
+		will use the incorrect information as if it were the
63
+		source address of the request.  This may enable remote
64
+		hosts to bypass any access control restrictions that are
65
+		based on the client's source addresses.
66
+
67
+	For example:
68
+
69
+		acl localhost src 127.0.0.1
70
+		acl my_other_proxy srcdomain .proxy.example.com
71
+		follow_x_forwarded_for allow localhost
72
+		follow_x_forwarded_for allow my_other_proxy
73
+DOC_END
74
+
75
+NAME: acl_uses_indirect_client
76
+COMMENT: on|off
77
+TYPE: onoff
78
+IFDEF: FOLLOW_X_FORWARDED_FOR
79
+DEFAULT: on
80
+LOC: Config.onoff.acl_uses_indirect_client
81
+DOC_START
82
+	Controls whether the indirect client address
83
+	(see follow_x_forwarded_for) is used instead of the
84
+	direct client address in acl matching.
85
+DOC_END
86
+
87
+NAME: delay_pool_uses_indirect_client
88
+COMMENT: on|off
89
+TYPE: onoff
90
+IFDEF: FOLLOW_X_FORWARDED_FOR && DELAY_POOLS
91
+DEFAULT: on
92
+LOC: Config.onoff.delay_pool_uses_indirect_client
93
+DOC_START
94
+	Controls whether the indirect client address
95
+	(see follow_x_forwarded_for) is used instead of the
96
+	direct client address in delay pools.
97
+DOC_END
98
+
99
+NAME: log_uses_indirect_client
100
+COMMENT: on|off
101
+TYPE: onoff
102
+IFDEF: FOLLOW_X_FORWARDED_FOR
103
+DEFAULT: on
104
+LOC: Config.onoff.log_uses_indirect_client
105
+DOC_START
106
+	Controls whether the indirect client address
107
+	(see follow_x_forwarded_for) is used instead of the
108
+	direct client address in the access log.
109
+DOC_END
110
+
111
 NAME: http_access
112
 TYPE: acl_access
113
 LOC: Config.accessList.http
114
Index: src/client_side.c
115
--- src/client_side.c	2 Sep 2003 02:13:45 -0000	1.47.2.39
116
+++ src/client_side.c	23 Nov 2003 14:20:22 -0000
117
@@ -109,6 +109,11 @@
118
 #if USE_IDENT
119
 static IDCB clientIdentDone;
120
 #endif
121
+#if FOLLOW_X_FORWARDED_FOR
122
+static void clientFollowXForwardedForStart(void *data);
123
+static void clientFollowXForwardedForNext(void *data);
124
+static void clientFollowXForwardedForDone(int answer, void *data);
125
+#endif /* FOLLOW_X_FORWARDED_FOR */
126
 static int clientOnlyIfCached(clientHttpRequest * http);
127
 static STCB clientSendMoreData;
128
 static STCB clientCacheHit;
129
@@ -177,10 +182,179 @@
130
     return ch;
131
 }
132
 
133
+#if FOLLOW_X_FORWARDED_FOR
134
+/*
135
+ * clientFollowXForwardedForStart() copies the X-Forwarded-For
136
+ * header into x_forwarded_for_iterator and passes control to
137
+ * clientFollowXForwardedForNext().
138
+ *
139
+ * clientFollowXForwardedForNext() checks the indirect_client_addr
140
+ * against the followXFF ACL and passes the result to
141
+ * clientFollowXForwardedForDone().
142
+ *
143
+ * clientFollowXForwardedForDone() either grabs the next address
144
+ * from the tail of x_forwarded_for_iterator and loops back to
145
+ * clientFollowXForwardedForNext(), or cleans up and passes control to
146
+ * clientAccessCheck().
147
+ */
148
+
149
+static void
150
+clientFollowXForwardedForStart(void *data)
151
+{
152
+    clientHttpRequest *http = data;
153
+    request_t *request = http->request;
154
+    if (Config.accessList.followXFF
155
+	&& httpHeaderHas(&request->header, HDR_X_FORWARDED_FOR))
156
+    {
157
+	request->x_forwarded_for_iterator = httpHeaderGetList(
158
+			&request->header, HDR_X_FORWARDED_FOR);
159
+	debug(33, 5) ("clientFollowXForwardedForStart: indirect_client_addr=%s XFF='%s'\n",
160
+			inet_ntoa(request->indirect_client_addr),
161
+			strBuf(request->x_forwarded_for_iterator));
162
+	clientFollowXForwardedForNext(http);
163
+    } else {
164
+	/* not configured to follow X-Forwarded-For, or nothing to follow */
165
+	debug(33, 5) ("clientFollowXForwardedForStart: nothing to do\n");
166
+	clientFollowXForwardedForDone(-1, http);
167
+    }
168
+}
169
+
170
+static void
171
+clientFollowXForwardedForNext(void *data)
172
+{
173
+    clientHttpRequest *http = data;
174
+    request_t *request = http->request;
175
+    debug(33, 5) ("clientFollowXForwardedForNext: indirect_client_addr=%s XFF='%s'\n",
176
+		    inet_ntoa(request->indirect_client_addr),
177
+		    strBuf(request->x_forwarded_for_iterator));
178
+    if (strLen(request->x_forwarded_for_iterator) != 0) {
179
+	/* check the acl to see whether to believe the X-Forwarded-For header */
180
+	http->acl_checklist = clientAclChecklistCreate(
181
+			Config.accessList.followXFF, http);
182
+	aclNBCheck(http->acl_checklist, clientFollowXForwardedForDone, http);
183
+    } else {
184
+	/* nothing left to follow */
185
+	debug(33, 5) ("clientFollowXForwardedForNext: nothing more to do\n");
186
+	clientFollowXForwardedForDone(-1, http);
187
+    }
188
+}
189
+
190
+static void
191
+clientFollowXForwardedForDone(int answer, void *data)
192
+{
193
+    clientHttpRequest *http = data;
194
+    request_t *request = http->request;
195
+    /*
196
+     * answer should be be ACCESS_ALLOWED or ACCESS_DENIED if we are
197
+     * called as a result of ACL checks, or -1 if we are called when
198
+     * there's nothing left to do.
199
+     */
200
+    if (answer == ACCESS_ALLOWED) {
201
+	/*
202
+	 * The IP address currently in request->indirect_client_addr
203
+	 * is trusted to use X-Forwarded-For.  Remove the last
204
+	 * comma-delimited element from x_forwarded_for_iterator and use
205
+	 * it to to replace indirect_client_addr, then repeat the cycle.
206
+	 */
207
+	const char *p;
208
+	const char *asciiaddr;
209
+	int l;
210
+	struct in_addr addr;
211
+	debug(33, 5) ("clientFollowXForwardedForDone: indirect_client_addr=%s is trusted\n",
212
+			inet_ntoa(request->indirect_client_addr));
213
+	p = strBuf(request->x_forwarded_for_iterator);
214
+	l = strLen(request->x_forwarded_for_iterator);
215
+
216
+	/*
217
+	 * XXX x_forwarded_for_iterator should really be a list of
218
+	 * IP addresses, but it's a String instead.  We have to
219
+	 * walk backwards through the String, biting off the last
220
+	 * comma-delimited part each time.  As long as the data is in
221
+	 * a String, we should probably implement and use a variant of
222
+	 * strListGetItem() that walks backwards instead of forwards
223
+	 * through a comma-separated list.  But we don't even do that;
224
+	 * we just do the work in-line here.
225
+	 */
226
+	/* skip trailing space and commas */
227
+	while (l > 0 && (p[l-1] == ',' || xisspace(p[l-1])))
228
+	    l--;
229
+	strCut(request->x_forwarded_for_iterator, l);
230
+	/* look for start of last item in list */
231
+	while (l > 0 && ! (p[l-1] == ',' || xisspace(p[l-1])))
232
+	    l--;
233
+	asciiaddr = p+l;
234
+	if (inet_aton(asciiaddr, &addr) == 0) {
235
+	    /* the address is not well formed; do not use it */
236
+	    debug(33, 3) ("clientFollowXForwardedForDone: malformed address '%s'\n",
237
+			    asciiaddr);
238
+	    goto done;
239
+	}
240
+	debug(33, 3) ("clientFollowXForwardedForDone: changing indirect_client_addr from %s to '%s'\n",
241
+		    inet_ntoa(request->indirect_client_addr),
242
+		    asciiaddr);
243
+	request->indirect_client_addr = addr;
244
+	strCut(request->x_forwarded_for_iterator, l);
245
+	if (! Config.onoff.acl_uses_indirect_client) {
246
+	    /*
247
+	     * If acl_uses_indirect_client is off, then it's impossible
248
+	     * to follow more than one level of X-Forwarded-For.
249
+	     */
250
+	    goto done;
251
+	}
252
+	clientFollowXForwardedForNext(http);
253
+	return;
254
+    } else if (answer == ACCESS_DENIED) {
255
+	debug(33, 5) ("clientFollowXForwardedForDone: indirect_client_addr=%s not trusted\n",
256
+			inet_ntoa(request->indirect_client_addr));
257
+    } else {
258
+	debug(33, 5) ("clientFollowXForwardedForDone: indirect_client_addr=%s nothing more to do\n",
259
+			inet_ntoa(request->indirect_client_addr));
260
+    }
261
+done:
262
+    /* clean up, and pass control to clientAccessCheck */
263
+    debug(33, 6) ("clientFollowXForwardedForDone: cleanup\n");
264
+    if (Config.onoff.log_uses_indirect_client) {
265
+	/*
266
+	 * Ensure that the access log shows the indirect client
267
+	 * instead of the direct client.
268
+	 */
269
+	ConnStateData *conn = http->conn;
270
+	conn->log_addr = request->indirect_client_addr;
271
+	conn->log_addr.s_addr &= Config.Addrs.client_netmask.s_addr;
272
+	debug(33, 3) ("clientFollowXForwardedForDone: setting log_addr=%s\n",
273
+			inet_ntoa(conn->log_addr));
274
+    }
275
+    stringClean(&request->x_forwarded_for_iterator);
276
+    request->flags.done_follow_x_forwarded_for = 1;
277
+    http->acl_checklist = NULL; /* XXX do we need to aclChecklistFree() ? */
278
+    clientAccessCheck(http);
279
+}
280
+#endif /* FOLLOW_X_FORWARDED_FOR */
281
+
282
 void
283
 clientAccessCheck(void *data)
284
 {
285
     clientHttpRequest *http = data;
286
+#if FOLLOW_X_FORWARDED_FOR
287
+    if (! http->request->flags.done_follow_x_forwarded_for
288
+        && httpHeaderHas(&http->request->header, HDR_X_FORWARDED_FOR))
289
+    {
290
+	/*
291
+	 * There's an X-ForwardedFor header and we haven't yet tried
292
+	 * to follow it to find the indirect_client_addr.  Follow it now.
293
+	 * clientFollowXForwardedForDone() will eventually pass control
294
+	 * back to us.
295
+	 *
296
+	 * XXX perhaps our caller should have called
297
+	 *     clientFollowXForwardedForStart instead.  Then we wouldn't
298
+	 *     need to do this little dance transferring control over
299
+	 *     there and then back here, and we wouldn't need the
300
+	 *     done_follow_x_forwarded_for flag.
301
+	 */
302
+	clientFollowXForwardedForStart(data);
303
+	return;
304
+    }
305
+#endif /* FOLLOW_X_FORWARDED_FOR */
306
     if (checkAccelOnly(http)) {
307
 	/* deny proxy requests in accel_only mode */
308
 	debug(33, 1) ("clientAccessCheck: proxy request denied in accel_only mode\n");
309
@@ -325,6 +499,9 @@
310
 	new_request->http_ver = old_request->http_ver;
311
 	httpHeaderAppend(&new_request->header, &old_request->header);
312
 	new_request->client_addr = old_request->client_addr;
313
+#if FOLLOW_X_FORWARDED_FOR
314
+	new_request->indirect_client_addr = old_request->indirect_client_addr;
315
+#endif /* FOLLOW_X_FORWARDED_FOR */
316
 	new_request->my_addr = old_request->my_addr;
317
 	new_request->my_port = old_request->my_port;
318
 	new_request->flags.redirected = 1;
319
@@ -3051,6 +3228,9 @@
320
 	    safe_free(http->log_uri);
321
 	    http->log_uri = xstrdup(urlCanonicalClean(request));
322
 	    request->client_addr = conn->peer.sin_addr;
323
+#if FOLLOW_X_FORWARDED_FOR
324
+	    request->indirect_client_addr = request->client_addr;
325
+#endif /* FOLLOW_X_FORWARDED_FOR */
326
 	    request->my_addr = conn->me.sin_addr;
327
 	    request->my_port = ntohs(conn->me.sin_port);
328
 	    request->http_ver = http->http_ver;
329
Index: src/delay_pools.c
330
--- src/delay_pools.c	19 Jun 2003 02:13:57 -0000	1.5.54.6
331
+++ src/delay_pools.c	23 Nov 2003 14:20:23 -0000
332
@@ -318,6 +318,11 @@
333
     r = http->request;
334
 
335
     memset(&ch, '\0', sizeof(ch));
336
+#if FOLLOW_X_FORWARDED_FOR
337
+    if (Config.onoff.delay_pool_uses_indirect_client) {
338
+	ch.src_addr = r->indirect_client_addr;
339
+    } else
340
+#endif /* FOLLOW_X_FORWARDED_FOR */
341
     ch.src_addr = r->client_addr;
342
     ch.my_addr = r->my_addr;
343
     ch.my_port = r->my_port;
344
*** src/structs.h.orig	Sun Jun 26 12:45:58 2005
345
--- src/structs.h	Sun Jun 26 12:48:45 2005
346
***************
347
*** 610,615 ****
348
--- 610,620 ----
349
  	int accel_uses_host_header;
350
  	int accel_no_pmtu_disc;
351
  	int global_internal_static;
352
+ #if FOLLOW_X_FORWARDED_FOR
353
+ 	int acl_uses_indirect_client;
354
+ 	int delay_pool_uses_indirect_client;
355
+ 	int log_uses_indirect_client;
356
+ #endif /* FOLLOW_X_FORWARDED_FOR */
357
      } onoff;
358
      acl *aclList;
359
      struct {
360
***************
361
*** 631,636 ****
362
--- 636,644 ----
363
  	acl_access *reply;
364
  	acl_address *outgoing_address;
365
  	acl_tos *outgoing_tos;
366
+ #if FOLLOW_X_FORWARDED_FOR
367
+ 	acl_access *followXFF;
368
+ #endif /* FOLLOW_X_FORWARDED_FOR */
369
      } accessList;
370
      acl_deny_info_list *denyInfoList;
371
      struct _authConfig {
372
***************
373
*** 1623,1628 ****
374
--- 1631,1641 ----
375
      unsigned int body_sent:1;
376
      unsigned int reset_tcp:1;
377
      unsigned int must_keepalive:1;
378
+ #if FOLLOW_X_FORWARDED_FOR
379
+     /* XXX this flag could be eliminated;
380
+      * see comments in clientAccessCheck */
381
+     unsigned int done_follow_x_forwarded_for;
382
+ #endif /* FOLLOW_X_FORWARDED_FOR */
383
  };
384
  
385
  struct _link_list {
386
***************
387
*** 1666,1671 ****
388
--- 1679,1687 ----
389
      int max_forwards;
390
      /* these in_addr's could probably be sockaddr_in's */
391
      struct in_addr client_addr;
392
+ #if FOLLOW_X_FORWARDED_FOR
393
+     struct in_addr indirect_client_addr; /* after following X-Forwarded-For */
394
+ #endif /* FOLLOW_X_FORWARDED_FOR */
395
      struct in_addr my_addr;
396
      unsigned short my_port;
397
      HttpHeader header;
398
***************
399
*** 1677,1682 ****
400
--- 1693,1703 ----
401
      const char *vary_headers;	/* Used when varying entities are detected. Changes how the store key is calculated */
402
      BODY_HANDLER *body_reader;
403
      void *body_reader_data;
404
+ #if FOLLOW_X_FORWARDED_FOR
405
+     /* XXX a list of IP addresses would be a better data structure
406
+      * than this String */
407
+     String x_forwarded_for_iterator;
408
+ #endif /* FOLLOW_X_FORWARDED_FOR */
409
  };
410
  
411
  struct _cachemgr_passwd {
(-)files/icap-2.5-bootstrap.patch (-422 lines)
Lines 1-422 Link Here
1
Patch 2 of 2 to integrate the icap-2_5 branch into the FreeBSD squid port.
2
3
Created by Thomas-Martin Seck <tmseck@netcologne.de>.
4
5
This patch simulates the autotools bootstrap necessary after applying the
6
ICAP patchset.
7
8
Please see icap-2.5-core.patch for further information.
9
10
Patch last updated: 2005-12-17
11
12
--- configure.orig	Sat Oct 22 11:56:01 2005
13
+++ configure	Sat Dec 17 17:45:21 2005
14
@@ -70,6 +70,8 @@
15
 ac_help="$ac_help
16
   --enable-delay-pools    Enable delay pools to limit bandwidth usage"
17
 ac_help="$ac_help
18
+  --enable-icap-support   	   Enable iCAP client capability"
19
+ac_help="$ac_help
20
   --enable-useragent-log  Enable logging of User-Agent header"
21
 ac_help="$ac_help
22
   --enable-referer-log    Enable logging of Referer header"
23
@@ -2170,6 +2172,38 @@
24
 
25
 
26
 
27
+
28
+if false; then
29
+  USE_ICAP_TRUE=
30
+  USE_ICAP_FALSE='#'
31
+else
32
+  USE_ICAP_TRUE='#'
33
+  USE_ICAP_FALSE=
34
+fi
35
+# Check whether --enable-icap-support or --disable-icap-support was given.
36
+if test "${enable_icap_support+set}" = set; then
37
+  enableval="$enable_icap_support"
38
+   if test "$enableval" = "yes" ; then
39
+    echo "ICAP support enabled"
40
+    cat >> confdefs.h <<\EOF
41
+#define HS_FEAT_ICAP 1
42
+EOF
43
+
44
+    
45
+
46
+if true; then
47
+  USE_ICAP_TRUE=
48
+  USE_ICAP_FALSE='#'
49
+else
50
+  USE_ICAP_TRUE='#'
51
+  USE_ICAP_FALSE=
52
+fi
53
+  fi
54
+
55
+fi
56
+
57
+
58
+
59
 # Check whether --enable-useragent-log or --disable-useragent-log was given.
60
 if test "${enable_useragent_log+set}" = set; then
61
   enableval="$enable_useragent_log"
62
@@ -7428,14 +7462,14 @@
63
         fi
64
     ;;
65
     esac
66
-    echo $ac_n "checking for main in -lpthread""... $ac_c" 1>&6
67
-echo "configure:7433: checking for main in -lpthread" >&5
68
+    echo $ac_n "checking for main in -pthread""... $ac_c" 1>&6
69
+echo "configure:7433: checking for main in -pthread" >&5
70
 ac_lib_var=`echo pthread'_'main | sed 'y%./+-%__p_%'`
71
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
72
   echo $ac_n "(cached) $ac_c" 1>&6
73
 else
74
   ac_save_LIBS="$LIBS"
75
-LIBS="-lpthread  $LIBS"
76
+LIBS="-pthread  $LIBS"
77
 cat > conftest.$ac_ext <<EOF
78
 #line 7441 "configure"
79
 #include "confdefs.h"
80
@@ -7465,7 +7499,7 @@
81
 #define $ac_tr_lib 1
82
 EOF
83
 
84
-  LIBS="-lpthread $LIBS"
85
+  LIBS="-pthread $LIBS"
86
 
87
 else
88
   echo "$ac_t""no" 1>&6
89
@@ -7769,6 +7803,8 @@
90
 	srand48 \
91
 	srandom \
92
 	statfs \
93
+	strnstr \
94
+	strcasestr \
95
 	strtoll \
96
 	sysconf \
97
 	syslog \
98
@@ -7898,6 +7934,50 @@
99
 fi
100
 fi
101
 
102
+
103
+if false; then
104
+  NEED_OWN_STRNSTR_TRUE=
105
+  NEED_OWN_STRNSTR_FALSE='#'
106
+else
107
+  NEED_OWN_STRNSTR_TRUE='#'
108
+  NEED_OWN_STRNSTR_FALSE=
109
+fi
110
+if test "$ac_cv_func_strnstr" = "no" || test "$ac_cv_func_vstrnstr" = "no" ; then
111
+  
112
+
113
+if true; then
114
+  NEED_OWN_STRNSTR_TRUE=
115
+  NEED_OWN_STRNSTR_FALSE='#'
116
+else
117
+  NEED_OWN_STRNSTR_TRUE='#'
118
+  NEED_OWN_STRNSTR_FALSE=
119
+fi
120
+fi
121
+
122
+
123
+
124
+if false; then
125
+  NEED_OWN_STRCASESTR_TRUE=
126
+  NEED_OWN_STRCASESTR_FALSE='#'
127
+else
128
+  NEED_OWN_STRCASESTR_TRUE='#'
129
+  NEED_OWN_STRCASESTR_FALSE=
130
+fi
131
+if test "$ac_cv_func_strcasestr" = "no" || test "$ac_cv_func_vstrcasestr" = "no"; then
132
+  
133
+
134
+if true; then
135
+  NEED_OWN_STRCASESTR_TRUE=
136
+  NEED_OWN_STRCASESTR_FALSE='#'
137
+else
138
+  NEED_OWN_STRCASESTR_TRUE='#'
139
+  NEED_OWN_STRCASESTR_FALSE=
140
+fi
141
+fi
142
+
143
+
144
+
145
+
146
 echo $ac_n "checking if va_copy is implemented""... $ac_c" 1>&6
147
 echo "configure:7903: checking if va_copy is implemented" >&5
148
 if eval "test \"`echo '$''{'ac_cv_func_va_copy'+set}'`\" = set"; then
149
@@ -9072,6 +9152,8 @@
150
 s%@ENABLE_PINGER_FALSE@%$ENABLE_PINGER_FALSE%g
151
 s%@USE_DELAY_POOLS_TRUE@%$USE_DELAY_POOLS_TRUE%g
152
 s%@USE_DELAY_POOLS_FALSE@%$USE_DELAY_POOLS_FALSE%g
153
+s%@USE_ICAP_TRUE@%$USE_ICAP_TRUE%g
154
+s%@USE_ICAP_FALSE@%$USE_ICAP_FALSE%g
155
 s%@USE_SNMP_TRUE@%$USE_SNMP_TRUE%g
156
 s%@USE_SNMP_FALSE@%$USE_SNMP_FALSE%g
157
 s%@SNMPLIB@%$SNMPLIB%g
158
@@ -9118,6 +9200,10 @@
159
 s%@LIB_LBER@%$LIB_LBER%g
160
 s%@NEED_OWN_SNPRINTF_TRUE@%$NEED_OWN_SNPRINTF_TRUE%g
161
 s%@NEED_OWN_SNPRINTF_FALSE@%$NEED_OWN_SNPRINTF_FALSE%g
162
+s%@NEED_OWN_STRNSTR_TRUE@%$NEED_OWN_STRNSTR_TRUE%g
163
+s%@NEED_OWN_STRNSTR_FALSE@%$NEED_OWN_STRNSTR_FALSE%g
164
+s%@NEED_OWN_STRCASESTR_TRUE@%$NEED_OWN_STRCASESTR_TRUE%g
165
+s%@NEED_OWN_STRCASESTR_FALSE@%$NEED_OWN_STRCASESTR_FALSE%g
166
 s%@REGEXLIB@%$REGEXLIB%g
167
 s%@LIBREGEX@%$LIBREGEX%g
168
 s%@LIBOBJS@%$LIBOBJS%g
169
--- include/autoconf.h.in.orig	Tue Sep 13 02:12:34 2005
170
+++ include/autoconf.h.in	Sat Dec 17 17:45:21 2005
171
@@ -124,6 +124,11 @@
172
  */
173
 #undef DELAY_POOLS
174
 
175
+/* 
176
+ * ICAP - Internet Content Adaptation Protocol
177
+ */
178
+#undef HS_FEAT_ICAP
179
+
180
 /*
181
  * If you want to log User-Agent request header values, define this.
182
  * By default, they are written to useragent.log in the Squid log
183
@@ -574,6 +579,12 @@
184
 
185
 /* Define if you have the statfs function.  */
186
 #undef HAVE_STATFS
187
+
188
+/* Define if you have the strcasestr function. */
189
+#undef HAVE_STRCASESTR
190
+
191
+/* Define if you have the strnstr function. */
192
+#undef HAVE_STRNSTR
193
 
194
 /* Define if you have the strerror function.  */
195
 #undef HAVE_STRERROR
196
--- lib/Makefile.in.orig	Wed Sep 28 22:57:20 2005
197
+++ lib/Makefile.in	Sat Dec 17 17:45:21 2005
198
@@ -123,6 +123,13 @@
199
 
200
 @NEED_OWN_SNPRINTF_TRUE@SNPRINTFSOURCE = snprintf.c
201
 @NEED_OWN_SNPRINTF_FALSE@SNPRINTFSOURCE = 
202
+
203
+@NEED_OWN_STRNSTR_TRUE@STRNSTRSOURCE = strnstr.c
204
+@NEED_OWN_STRNSTR_FALSE@STRNSTRSOURCE = 
205
+
206
+@NEED_OWN_STRCASESTR_TRUE@STRCASESTRSOURCE = strcasestr.c
207
+@NEED_OWN_STRCASESTR_FALSE@STRCASESTRSOURCE = 
208
+
209
 @NEED_OWN_MD5_TRUE@MD5SOURCE = md5.c
210
 @NEED_OWN_MD5_FALSE@MD5SOURCE = 
211
 
212
@@ -158,6 +165,8 @@
213
 	$(SNPRINTFSOURCE) \
214
 	splay.c \
215
 	Stack.c \
216
+	$(STRNSTRSOURCE) \
217
+	$(STRCASESTRSOURCE) \
218
 	stub_memaccount.c \
219
 	util.c \
220
 	uudecode.c
221
@@ -196,13 +205,18 @@
222
 @NEED_OWN_MD5_FALSE@am__objects_1 =
223
 @NEED_OWN_SNPRINTF_FALSE@am__objects_2 =
224
 @NEED_OWN_SNPRINTF_TRUE@am__objects_2 = snprintf.$(OBJEXT)
225
+@NEED_OWN_STRNSTR_FALSE@am__objects_3 =
226
+@NEED_OWN_STRNSTR_TRUE@am__objects_3 = strnstr.$(OBJEXT)
227
+@NEED_OWN_STRCASESTR_TRUE@am__objects_4 = strcasestr.$(OBJEXT)
228
+@NEED_OWN_STRCASESTR_FALSE@am__objects_4 =
229
 am_libmiscutil_a_OBJECTS = Array.$(OBJEXT) base64.$(OBJEXT) \
230
 	getfullhostname.$(OBJEXT) hash.$(OBJEXT) heap.$(OBJEXT) \
231
 	html_quote.$(OBJEXT) iso3307.$(OBJEXT) $(am__objects_1) \
232
 	radix.$(OBJEXT) rfc1035.$(OBJEXT) rfc1123.$(OBJEXT) \
233
 	rfc1738.$(OBJEXT) rfc2617.$(OBJEXT) safe_inet_addr.$(OBJEXT) \
234
 	$(am__objects_2) splay.$(OBJEXT) Stack.$(OBJEXT) \
235
-	stub_memaccount.$(OBJEXT) util.$(OBJEXT) uudecode.$(OBJEXT)
236
+	$(am__objects_3) $(am__objects_4) stub_memaccount.$(OBJEXT) \
237
+	util.$(OBJEXT) uudecode.$(OBJEXT)
238
 libmiscutil_a_OBJECTS = $(am_libmiscutil_a_OBJECTS)
239
 libntlmauth_a_AR = $(AR) cru
240
 libntlmauth_a_DEPENDENCIES = @LIBOBJS@
241
@@ -224,15 +238,16 @@
242
 @AMDEP_TRUE@	$(DEPDIR)/dlmalloc.Po $(DEPDIR)/drand48.Po \
243
 @AMDEP_TRUE@	$(DEPDIR)/getfullhostname.Po $(DEPDIR)/hash.Po \
244
 @AMDEP_TRUE@	$(DEPDIR)/heap.Po $(DEPDIR)/html_quote.Po \
245
-@AMDEP_TRUE@	$(DEPDIR)/inet_ntoa.Po $(DEPDIR)/initgroups.Po \
246
-@AMDEP_TRUE@	$(DEPDIR)/iso3307.Po $(DEPDIR)/md5.Po \
247
-@AMDEP_TRUE@	$(DEPDIR)/ntlmauth.Po $(DEPDIR)/radix.Po \
248
-@AMDEP_TRUE@	$(DEPDIR)/rfc1035.Po $(DEPDIR)/rfc1123.Po \
249
-@AMDEP_TRUE@	$(DEPDIR)/rfc1738.Po $(DEPDIR)/rfc2617.Po \
250
-@AMDEP_TRUE@	$(DEPDIR)/safe_inet_addr.Po $(DEPDIR)/snprintf.Po \
251
-@AMDEP_TRUE@	$(DEPDIR)/splay.Po $(DEPDIR)/strerror.Po \
252
-@AMDEP_TRUE@	$(DEPDIR)/stub_memaccount.Po $(DEPDIR)/tempnam.Po \
253
-@AMDEP_TRUE@	$(DEPDIR)/util.Po $(DEPDIR)/uudecode.Po
254
+@AMDEP_TRUE@	$(DEPDIR)/inet_ntoa.Po $(DEPDIR)/iso3307.Po \
255
+@AMDEP_TRUE@	$(DEPDIR)/md5.Po $(DEPDIR)/ntlmauth.Po \
256
+@AMDEP_TRUE@	$(DEPDIR)/radix.Po $(DEPDIR)/rfc1035.Po \
257
+@AMDEP_TRUE@	$(DEPDIR)/rfc1123.Po $(DEPDIR)/rfc1738.Po \
258
+@AMDEP_TRUE@	$(DEPDIR)/rfc2617.Po $(DEPDIR)/safe_inet_addr.Po \
259
+@AMDEP_TRUE@	$(DEPDIR)/snprintf.Po $(DEPDIR)/splay.Po \
260
+@AMDEP_TRUE@	$(DEPDIR)/strcasestr.Po $(DEPDIR)/strerror.Po \
261
+@AMDEP_TRUE@	$(DEPDIR)/strnstr.Po $(DEPDIR)/stub_memaccount.Po \
262
+@AMDEP_TRUE@	$(DEPDIR)/tempnam.Po $(DEPDIR)/util.Po \
263
+@AMDEP_TRUE@	$(DEPDIR)/uudecode.Po
264
 COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
265
 	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
266
 CCLD = $(CC)
267
@@ -241,8 +256,8 @@
268
 DIST_SOURCES = $(libdlmalloc_a_SOURCES) $(libmiscutil_a_SOURCES) \
269
 	$(EXTRA_libmiscutil_a_SOURCES) $(libntlmauth_a_SOURCES) \
270
 	$(libregex_a_SOURCES)
271
-DIST_COMMON = Makefile.am Makefile.in drand48.c inet_ntoa.c \
272
-	initgroups.c strerror.c tempnam.c
273
+DIST_COMMON = Makefile.am Makefile.in drand48.c inet_ntoa.c strerror.c \
274
+	tempnam.c
275
 SOURCES = $(libdlmalloc_a_SOURCES) $(libmiscutil_a_SOURCES) $(EXTRA_libmiscutil_a_SOURCES) $(libntlmauth_a_SOURCES) $(libregex_a_SOURCES)
276
 
277
 all: all-am
278
@@ -295,7 +310,6 @@
279
 @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/heap.Po@am__quote@
280
 @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/html_quote.Po@am__quote@
281
 @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/inet_ntoa.Po@am__quote@
282
-@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/initgroups.Po@am__quote@
283
 @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/iso3307.Po@am__quote@
284
 @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/md5.Po@am__quote@
285
 @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/ntlmauth.Po@am__quote@
286
@@ -307,7 +321,9 @@
287
 @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/safe_inet_addr.Po@am__quote@
288
 @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/snprintf.Po@am__quote@
289
 @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/splay.Po@am__quote@
290
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/strcasestr.Po@am__quote@
291
 @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/strerror.Po@am__quote@
292
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/strnstr.Po@am__quote@
293
 @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/stub_memaccount.Po@am__quote@
294
 @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/tempnam.Po@am__quote@
295
 @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/util.Po@am__quote@
296
--- src/Makefile.in.orig	Wed Sep 28 22:57:21 2005
297
+++ src/Makefile.in	Sat Dec 17 17:45:21 2005
298
@@ -125,6 +125,9 @@
299
 install_sh = @install_sh@
300
 makesnmplib = @makesnmplib@
301
 
302
+@USE_ICAP_TRUE@ICAPSOURCE = icap_common.c icap_reqmod.c icap_respmod.c icap_opt.c
303
+@USE_ICAP_FALSE@ICAPSOURCE = 
304
+
305
 @USE_DNSSERVER_TRUE@DNSSOURCE = dns.c
306
 @USE_DNSSERVER_FALSE@DNSSOURCE = dns_internal.c
307
 @USE_DNSSERVER_TRUE@DNSSERVER = dnsserver
308
@@ -249,6 +252,7 @@
309
 	HttpMsg.c \
310
 	HttpReply.c \
311
 	HttpRequest.c \
312
+	$(ICAPSOURCE) \
313
 	icmp.c \
314
 	icp_v2.c \
315
 	icp_v3.c \
316
@@ -468,54 +472,58 @@
317
 pinger_LDADD = $(LDADD)
318
 pinger_DEPENDENCIES =
319
 pinger_LDFLAGS =
320
-@USE_DELAY_POOLS_TRUE@am__objects_3 = delay_pools.$(OBJEXT)
321
-@USE_DELAY_POOLS_FALSE@am__objects_3 =
322
-@USE_DNSSERVER_FALSE@am__objects_4 = dns_internal.$(OBJEXT)
323
-@USE_DNSSERVER_TRUE@am__objects_4 = dns.$(OBJEXT)
324
-@ENABLE_HTCP_TRUE@am__objects_5 = htcp.$(OBJEXT)
325
-@MAKE_LEAKFINDER_FALSE@am__objects_6 =
326
-@MAKE_LEAKFINDER_TRUE@am__objects_6 = leakfinder.$(OBJEXT)
327
-@USE_SNMP_TRUE@am__objects_7 = snmp_core.$(OBJEXT) snmp_agent.$(OBJEXT)
328
-@USE_SNMP_FALSE@am__objects_7 =
329
-@ENABLE_SSL_TRUE@am__objects_8 = ssl_support.$(OBJEXT)
330
-@ENABLE_SSL_FALSE@am__objects_8 =
331
-@ENABLE_UNLINKD_FALSE@am__objects_9 =
332
-@ENABLE_UNLINKD_TRUE@am__objects_9 = unlinkd.$(OBJEXT)
333
-@ENABLE_WIN32SPECIFIC_TRUE@am__objects_10 = win32.$(OBJEXT)
334
-@ENABLE_WIN32SPECIFIC_FALSE@am__objects_10 =
335
+@USE_DELAY_POOLS_FALSE@am__objects_5 =
336
+@USE_DELAY_POOLS_TRUE@am__objects_5 = delay_pools.$(OBJEXT)
337
+@USE_DNSSERVER_FALSE@am__objects_6 = dns_internal.$(OBJEXT)
338
+@USE_DNSSERVER_TRUE@am__objects_6 = dns.$(OBJEXT)
339
+@ENABLE_HTCP_TRUE@am__objects_7 = htcp.$(OBJEXT)
340
+@USE_ICAP_TRUE@am__objects_8 = icap_common.$(OBJEXT) \
341
+@USE_ICAP_TRUE@	icap_reqmod.$(OBJEXT) icap_respmod.$(OBJEXT) \
342
+@USE_ICAP_TRUE@	icap_opt.$(OBJEXT)
343
+@USE_ICAP_FALSE@am__objects_8 =
344
+@MAKE_LEAKFINDER_TRUE@am__objects_9 = leakfinder.$(OBJEXT)
345
+@MAKE_LEAKFINDER_FALSE@am__objects_9 =
346
+@USE_SNMP_TRUE@am__objects_10 = snmp_core.$(OBJEXT) snmp_agent.$(OBJEXT)
347
+@USE_SNMP_FALSE@am__objects_10 =
348
+@ENABLE_SSL_FALSE@am__objects_11 =
349
+@ENABLE_SSL_TRUE@am__objects_11 = ssl_support.$(OBJEXT)
350
+@ENABLE_UNLINKD_TRUE@am__objects_12 = unlinkd.$(OBJEXT)
351
+@ENABLE_UNLINKD_FALSE@am__objects_12 =
352
+@ENABLE_WIN32SPECIFIC_FALSE@am__objects_13 =
353
+@ENABLE_WIN32SPECIFIC_TRUE@am__objects_13 = win32.$(OBJEXT)
354
 am_squid_OBJECTS = access_log.$(OBJEXT) acl.$(OBJEXT) asn.$(OBJEXT) \
355
 	authenticate.$(OBJEXT) cache_cf.$(OBJEXT) CacheDigest.$(OBJEXT) \
356
 	cache_manager.$(OBJEXT) carp.$(OBJEXT) cbdata.$(OBJEXT) \
357
 	client_db.$(OBJEXT) client_side.$(OBJEXT) comm.$(OBJEXT) \
358
-	comm_select.$(OBJEXT) debug.$(OBJEXT) $(am__objects_3) \
359
-	disk.$(OBJEXT) $(am__objects_4) errorpage.$(OBJEXT) \
360
+	comm_select.$(OBJEXT) debug.$(OBJEXT) $(am__objects_5) \
361
+	disk.$(OBJEXT) $(am__objects_6) errorpage.$(OBJEXT) \
362
 	ETag.$(OBJEXT) event.$(OBJEXT) external_acl.$(OBJEXT) \
363
 	fd.$(OBJEXT) filemap.$(OBJEXT) forward.$(OBJEXT) \
364
 	fqdncache.$(OBJEXT) ftp.$(OBJEXT) gopher.$(OBJEXT) \
365
-	helper.$(OBJEXT) $(am__objects_5) http.$(OBJEXT) \
366
+	helper.$(OBJEXT) $(am__objects_7) http.$(OBJEXT) \
367
 	HttpStatusLine.$(OBJEXT) HttpHdrCc.$(OBJEXT) \
368
 	HttpHdrRange.$(OBJEXT) HttpHdrContRange.$(OBJEXT) \
369
 	HttpHeader.$(OBJEXT) HttpHeaderTools.$(OBJEXT) \
370
 	HttpBody.$(OBJEXT) HttpMsg.$(OBJEXT) HttpReply.$(OBJEXT) \
371
-	HttpRequest.$(OBJEXT) icmp.$(OBJEXT) icp_v2.$(OBJEXT) \
372
-	icp_v3.$(OBJEXT) ident.$(OBJEXT) internal.$(OBJEXT) \
373
-	ipc.$(OBJEXT) ipcache.$(OBJEXT) $(am__objects_6) \
374
-	logfile.$(OBJEXT) main.$(OBJEXT) mem.$(OBJEXT) \
375
+	HttpRequest.$(OBJEXT) $(am__objects_8) icmp.$(OBJEXT) \
376
+	icp_v2.$(OBJEXT) icp_v3.$(OBJEXT) ident.$(OBJEXT) \
377
+	internal.$(OBJEXT) ipc.$(OBJEXT) ipcache.$(OBJEXT) \
378
+	$(am__objects_9) logfile.$(OBJEXT) main.$(OBJEXT) mem.$(OBJEXT) \
379
 	MemPool.$(OBJEXT) MemBuf.$(OBJEXT) mime.$(OBJEXT) \
380
 	multicast.$(OBJEXT) neighbors.$(OBJEXT) net_db.$(OBJEXT) \
381
 	Packer.$(OBJEXT) pconn.$(OBJEXT) peer_digest.$(OBJEXT) \
382
 	peer_select.$(OBJEXT) redirect.$(OBJEXT) referer.$(OBJEXT) \
383
-	refresh.$(OBJEXT) send-announce.$(OBJEXT) $(am__objects_7) \
384
-	ssl.$(OBJEXT) $(am__objects_8) stat.$(OBJEXT) \
385
+	refresh.$(OBJEXT) send-announce.$(OBJEXT) $(am__objects_10) \
386
+	ssl.$(OBJEXT) $(am__objects_11) stat.$(OBJEXT) \
387
 	StatHist.$(OBJEXT) String.$(OBJEXT) stmem.$(OBJEXT) \
388
 	store.$(OBJEXT) store_io.$(OBJEXT) store_client.$(OBJEXT) \
389
 	store_digest.$(OBJEXT) store_dir.$(OBJEXT) \
390
 	store_key_md5.$(OBJEXT) store_log.$(OBJEXT) \
391
 	store_rebuild.$(OBJEXT) store_swapin.$(OBJEXT) \
392
 	store_swapmeta.$(OBJEXT) store_swapout.$(OBJEXT) \
393
-	tools.$(OBJEXT) $(am__objects_9) url.$(OBJEXT) urn.$(OBJEXT) \
394
+	tools.$(OBJEXT) $(am__objects_12) url.$(OBJEXT) urn.$(OBJEXT) \
395
 	useragent.$(OBJEXT) wais.$(OBJEXT) wccp.$(OBJEXT) \
396
-	whois.$(OBJEXT) $(am__objects_10)
397
+	whois.$(OBJEXT) $(am__objects_13)
398
 nodist_squid_OBJECTS = repl_modules.$(OBJEXT) auth_modules.$(OBJEXT) \
399
 	store_modules.$(OBJEXT) globals.$(OBJEXT) \
400
 	string_arrays.$(OBJEXT)
401
@@ -563,7 +571,9 @@
402
 @AMDEP_TRUE@	$(DEPDIR)/fqdncache.Po $(DEPDIR)/ftp.Po \
403
 @AMDEP_TRUE@	$(DEPDIR)/globals.Po $(DEPDIR)/gopher.Po \
404
 @AMDEP_TRUE@	$(DEPDIR)/helper.Po $(DEPDIR)/htcp.Po \
405
-@AMDEP_TRUE@	$(DEPDIR)/http.Po $(DEPDIR)/icmp.Po \
406
+@AMDEP_TRUE@	$(DEPDIR)/http.Po $(DEPDIR)/icap_common.Po \
407
+@AMDEP_TRUE@	$(DEPDIR)/icap_opt.Po $(DEPDIR)/icap_reqmod.Po \
408
+@AMDEP_TRUE@	$(DEPDIR)/icap_respmod.Po $(DEPDIR)/icmp.Po \
409
 @AMDEP_TRUE@	$(DEPDIR)/icp_v2.Po $(DEPDIR)/icp_v3.Po \
410
 @AMDEP_TRUE@	$(DEPDIR)/ident.Po $(DEPDIR)/internal.Po \
411
 @AMDEP_TRUE@	$(DEPDIR)/ipc.Po $(DEPDIR)/ipcache.Po \
412
@@ -777,6 +787,10 @@
413
 @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/helper.Po@am__quote@
414
 @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/htcp.Po@am__quote@
415
 @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/http.Po@am__quote@
416
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/icap_common.Po@am__quote@
417
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/icap_opt.Po@am__quote@
418
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/icap_reqmod.Po@am__quote@
419
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/icap_respmod.Po@am__quote@
420
 @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/icmp.Po@am__quote@
421
 @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/icp_v2.Po@am__quote@
422
 @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/icp_v3.Po@am__quote@
(-)files/customlog-2.5.patch (-1597 lines)
Lines 1-1597 Link Here
1
! This patch is sourced from http://devel.squid-cache.org/customlog/
2
! Modified diff paths to apply cleanly
3
4
Index: src/access_log.c
5
diff -u src/access_log.c:1.15.6.8 src/access_log.c:1.15.6.3.2.15
6
--- src/access_log.c:1.15.6.8	Tue Mar 29 18:17:46 2005
7
+++ src/access_log.c	Mon May 15 03:58:22 2006
8
@@ -36,9 +36,6 @@
9
 
10
 #include "squid.h"
11
 
12
-static void accessLogSquid(AccessLogEntry * al);
13
-static void accessLogCommon(AccessLogEntry * al);
14
-static Logfile *logfile = NULL;
15
 #if HEADERS_LOG
16
 static Logfile *headerslog = NULL;
17
 #endif
18
@@ -234,8 +231,768 @@
19
     return username_quote(name);
20
 }
21
 
22
+static char *
23
+log_quoted_string(const char *str)
24
+{
25
+    char *out = xmalloc(strlen(str) * 2 + 1);
26
+    char *p = out;
27
+    while (*str) {
28
+	int l = strcspn(str, "\"\\\r\n\t");
29
+	memcpy(p, str, l);
30
+	str += l;
31
+	p += l;
32
+	switch (*str) {
33
+	case '\0':
34
+	    break;
35
+	case '\r':
36
+	    *p++ = '\\';
37
+	    *p++ = 'r';
38
+	    str++;
39
+	    break;
40
+	case '\n':
41
+	    *p++ = '\\';
42
+	    *p++ = 'n';
43
+	    str++;
44
+	    break;
45
+	case '\t':
46
+	    *p++ = '\\';
47
+	    *p++ = 't';
48
+	    str++;
49
+	    break;
50
+	default:
51
+	    *p++ = '\\';
52
+	    *p++ = *str;
53
+	    str++;
54
+	    break;
55
+	}
56
+    }
57
+    *p++ = '\0';
58
+    return out;
59
+}
60
+
61
+/*
62
+ * Bytecodes for the configureable logformat stuff
63
+ */
64
+typedef enum {
65
+    LFT_NONE,			/* dummy */
66
+    LFT_STRING,
67
+
68
+    LFT_CLIENT_IP_ADDRESS,
69
+    LFT_CLIENT_FQDN,
70
+/*LFT_CLIENT_PORT, */
71
+
72
+/*LFT_SERVER_IP_ADDRESS, */
73
+    LFT_SERVER_IP_OR_PEER_NAME,
74
+/*LFT_SERVER_PORT, */
75
+
76
+    LFT_LOCAL_IP,
77
+    LFT_LOCAL_PORT,
78
+/*LFT_LOCAL_NAME, */
79
+
80
+    LFT_TIME_SECONDS_SINCE_EPOCH,
81
+    LFT_TIME_SUBSECOND,
82
+    LFT_TIME_LOCALTIME,
83
+    LFT_TIME_GMT,
84
+    LFT_TIME_TO_HANDLE_REQUEST,
85
+
86
+    LFT_REQUEST_HEADER,
87
+    LFT_REQUEST_HEADER_ELEM,
88
+    LFT_REQUEST_ALL_HEADERS,
89
+
90
+    LFT_REPLY_HEADER,
91
+    LFT_REPLY_HEADER_ELEM,
92
+    LFT_REPLY_ALL_HEADERS,
93
+
94
+    LFT_USER_NAME,
95
+    LFT_USER_LOGIN,
96
+    LFT_USER_IDENT,
97
+/*LFT_USER_REALM, */
98
+/*LFT_USER_SCHEME, */
99
+
100
+    LFT_HTTP_CODE,
101
+/*LFT_HTTP_STATUS, */
102
+
103
+    LFT_SQUID_STATUS,
104
+/*LFT_SQUID_ERROR, */
105
+    LFT_SQUID_HIERARCHY,
106
+
107
+    LFT_MIME_TYPE,
108
+
109
+    LFT_REQUEST_METHOD,
110
+    LFT_REQUEST_URI,
111
+/*LFT_REQUEST_QUERY, * // * this is not needed. see strip_query_terms */
112
+    LFT_REQUEST_VERSION,
113
+
114
+/*LFT_REQUEST_SIZE_TOTAL, */
115
+/*LFT_REQUEST_SIZE_LINE, */
116
+/*LFT_REQUEST_SIZE_HEADERS, */
117
+/*LFT_REQUEST_SIZE_BODY, */
118
+/*LFT_REQUEST_SIZE_BODY_NO_TE, */
119
+
120
+    LFT_REPLY_SIZE_TOTAL,
121
+/*LFT_REPLY_SIZE_LINE, */
122
+/*LFT_REPLY_SIZE_HEADERS, */
123
+/*LFT_REPLY_SIZE_BODY, */
124
+/*LFT_REPLY_SIZE_BODY_NO_TE, */
125
+
126
+#ifdef HAVE_EXTACL_LOG
127
+    LFT_EXT_LOG,
128
+#endif
129
+
130
+    LFT_PERCENT			/* special string cases for escaped chars */
131
+} logformat_bcode_t;
132
+
133
+enum log_quote {
134
+    LOG_QUOTE_NONE = 0,
135
+    LOG_QUOTE_QUOTES,
136
+    LOG_QUOTE_BRAKETS,
137
+    LOG_QUOTE_URL,
138
+    LOG_QUOTE_RAW
139
+};
140
+struct _logformat_token {
141
+    logformat_bcode_t type;
142
+    union {
143
+	char *string;
144
+	struct {
145
+	    char *header;
146
+	    char *element;
147
+	    char separator;
148
+	} header;
149
+	char *timespec;
150
+    } data;
151
+    unsigned char width;
152
+    unsigned char precision;
153
+    enum log_quote quote:3;
154
+    unsigned int left:1;
155
+    unsigned int space:1;
156
+    unsigned int zero:1;
157
+    int divisor;
158
+    logformat_token *next;	/* todo: move from linked list to array */
159
+};
160
+
161
+struct logformat_token_table_entry {
162
+    const char *config;
163
+    logformat_bcode_t token_type;
164
+    int options;
165
+};
166
+
167
+struct logformat_token_table_entry logformat_token_table[] =
168
+{
169
+
170
+    {">a", LFT_CLIENT_IP_ADDRESS},
171
+/*{ ">p", LFT_CLIENT_PORT}, */
172
+    {">A", LFT_CLIENT_FQDN},
173
+
174
+/*{ "<a", LFT_SERVER_IP_ADDRESS }, */
175
+/*{ "<p", LFT_SERVER_PORT }, */
176
+    {"<A", LFT_SERVER_IP_OR_PEER_NAME},
177
+
178
+    {"la", LFT_LOCAL_IP},
179
+    {"lp", LFT_LOCAL_PORT},
180
+/*{ "lA", LFT_LOCAL_NAME }, */
181
+
182
+    {"ts", LFT_TIME_SECONDS_SINCE_EPOCH},
183
+    {"tu", LFT_TIME_SUBSECOND},
184
+    {"tl", LFT_TIME_LOCALTIME},
185
+    {"tg", LFT_TIME_GMT},
186
+    {"tr", LFT_TIME_TO_HANDLE_REQUEST},
187
+
188
+    {">h", LFT_REQUEST_HEADER},
189
+    {"<h", LFT_REPLY_HEADER},
190
+
191
+    {"un", LFT_USER_NAME},
192
+    {"ul", LFT_USER_LOGIN},
193
+/*{ "ur", LFT_USER_REALM }, */
194
+/*{ "us", LFT_USER_SCHEME }, */
195
+    {"ui", LFT_USER_IDENT},
196
+
197
+    {"Hs", LFT_HTTP_CODE},
198
+/*{ "Ht", LFT_HTTP_STATUS }, */
199
+
200
+    {"Ss", LFT_SQUID_STATUS},
201
+/*{ "Se", LFT_SQUID_ERROR }, */
202
+    {"Sh", LFT_SQUID_HIERARCHY},
203
+
204
+    {"mt", LFT_MIME_TYPE},
205
+
206
+    {"rm", LFT_REQUEST_METHOD},
207
+    {"ru", LFT_REQUEST_URI},	/* doesn't include the query-string */
208
+/* { "rq", LFT_REQUEST_QUERY }, * /     / * the query-string, INCLUDING the leading ? */
209
+    {">v", LFT_REQUEST_VERSION},
210
+    {"rv", LFT_REQUEST_VERSION},
211
+
212
+/*{ ">st", LFT_REQUEST_SIZE_TOTAL }, */
213
+/*{ ">sl", LFT_REQUEST_SIZE_LINE }, * / / * the request line "GET ... " */
214
+/*{ ">sh", LFT_REQUEST_SIZE_HEADERS }, */
215
+/*{ ">sb", LFT_REQUEST_SIZE_BODY }, */
216
+/*{ ">sB", LFT_REQUEST_SIZE_BODY_NO_TE }, */
217
+
218
+    {"<st", LFT_REPLY_SIZE_TOTAL},
219
+/*{ "<sl", LFT_REPLY_SIZE_LINE }, * /   / * the reply line (protocol, code, text) */
220
+/*{ "<sh", LFT_REPLY_SIZE_HEADERS }, */
221
+/*{ "<sb", LFT_REPLY_SIZE_BODY }, */
222
+/*{ "<sB", LFT_REPLY_SIZE_BODY_NO_TE }, */
223
+
224
+#ifdef HAVE_EXTACL_LOG
225
+    {"ea", LFT_EXT_LOG},
226
+#endif
227
+
228
+    {"%", LFT_PERCENT},
229
+
230
+    {NULL, LFT_NONE}		/* this must be last */
231
+};
232
+
233
+static void
234
+accessLogCustom(AccessLogEntry * al, customlog * log)
235
+{
236
+    logformat *lf;
237
+    Logfile *logfile;
238
+    logformat_token *fmt;
239
+    static MemBuf mb = MemBufNULL;
240
+    char tmp[1024];
241
+    String sb = StringNull;
242
+
243
+    memBufReset(&mb);
244
+
245
+    lf = log->logFormat;
246
+    logfile = log->logfile;
247
+    for (fmt = lf->format; fmt != NULL; fmt = fmt->next) {	/* for each token */
248
+	const char *out = NULL;
249
+	int quote = 0;
250
+	long int outint = 0;
251
+	int doint = 0;
252
+	int dofree = 0;
253
+	switch (fmt->type) {
254
+	case LFT_NONE:
255
+	    out = "";
256
+	    break;
257
+	case LFT_STRING:
258
+	    out = fmt->data.string;
259
+	    break;
260
+	case LFT_CLIENT_IP_ADDRESS:
261
+	    out = inet_ntoa(al->cache.caddr);
262
+	    break;
263
+
264
+	case LFT_CLIENT_FQDN:
265
+	    out = fqdncache_gethostbyaddr(al->cache.caddr, FQDN_LOOKUP_IF_MISS);
266
+	    if (!out)
267
+		out = inet_ntoa(al->cache.caddr);
268
+	    break;
269
+
270
+	    /* case LFT_CLIENT_PORT: */
271
+
272
+	    /* case LFT_SERVER_IP_ADDRESS: */
273
+
274
+	case LFT_SERVER_IP_OR_PEER_NAME:
275
+	    out = al->hier.host;
276
+	    break;
277
+
278
+	    /* case LFT_SERVER_PORT: */
279
+
280
+	case LFT_LOCAL_IP:
281
+	    if (al->request)
282
+		out = inet_ntoa(al->request->my_addr);
283
+	    break;
284
+
285
+	case LFT_LOCAL_PORT:
286
+	    if (al->request) {
287
+		outint = al->request->my_port;
288
+		doint = 1;
289
+	    }
290
+	    break;
291
+
292
+	case LFT_TIME_SECONDS_SINCE_EPOCH:
293
+	    outint = current_time.tv_sec;
294
+	    doint = 1;
295
+	    break;
296
+
297
+	case LFT_TIME_SUBSECOND:
298
+	    outint = current_time.tv_usec / fmt->divisor;
299
+	    doint = 1;
300
+	    break;
301
+
302
+
303
+	case LFT_TIME_LOCALTIME:
304
+	case LFT_TIME_GMT:
305
+	    {
306
+		const char *spec;
307
+		struct tm *t;
308
+		spec = fmt->data.timespec;
309
+		if (!spec)
310
+		    spec = "%d/%b/%Y:%H:%M:%S %z";
311
+		if (fmt->type == LFT_TIME_LOCALTIME)
312
+		    t = localtime(&squid_curtime);
313
+		else
314
+		    t = gmtime(&squid_curtime);
315
+		strftime(tmp, sizeof(tmp), spec, t);
316
+		out = tmp;
317
+	    }
318
+	    break;
319
+
320
+	case LFT_TIME_TO_HANDLE_REQUEST:
321
+	    outint = al->cache.msec;
322
+	    doint = 1;
323
+	    break;
324
+
325
+	case LFT_REQUEST_HEADER:
326
+	    if (al->request)
327
+		sb = httpHeaderGetByName(&al->request->header, fmt->data.header.header);
328
+	    out = strBuf(sb);
329
+	    quote = 1;
330
+	    break;
331
+
332
+	case LFT_REPLY_HEADER:
333
+	    if (al->reply)
334
+		sb = httpHeaderGetByName(&al->reply->header, fmt->data.header.header);
335
+	    out = strBuf(sb);
336
+	    quote = 1;
337
+	    break;
338
+
339
+	case LFT_REQUEST_HEADER_ELEM:
340
+	    if (al->request)
341
+		sb = httpHeaderGetByNameListMember(&al->request->header, fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
342
+	    out = strBuf(sb);
343
+	    quote = 1;
344
+	    break;
345
+
346
+	case LFT_REPLY_HEADER_ELEM:
347
+	    if (al->reply)
348
+		sb = httpHeaderGetByNameListMember(&al->reply->header, fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
349
+	    out = strBuf(sb);
350
+	    quote = 1;
351
+	    break;
352
+
353
+	case LFT_REQUEST_ALL_HEADERS:
354
+	    out = al->headers.request;
355
+	    quote = 1;
356
+	    break;
357
+
358
+	case LFT_REPLY_ALL_HEADERS:
359
+	    out = al->headers.reply;
360
+	    quote = 1;
361
+	    break;
362
+
363
+	case LFT_USER_NAME:
364
+	    out = accessLogFormatName(al->cache.authuser ?
365
+		al->cache.authuser : al->cache.rfc931);
366
+	    dofree = 1;
367
+	    break;
368
+
369
+	case LFT_USER_LOGIN:
370
+	    out = accessLogFormatName(al->cache.authuser);
371
+	    dofree = 1;
372
+	    break;
373
+
374
+	case LFT_USER_IDENT:
375
+	    out = accessLogFormatName(al->cache.rfc931);
376
+	    dofree = 1;
377
+	    break;
378
+
379
+	    /* case LFT_USER_REALM: */
380
+	    /* case LFT_USER_SCHEME: */
381
+
382
+	case LFT_HTTP_CODE:
383
+	    outint = al->http.code;
384
+	    doint = 1;
385
+	    break;
386
+
387
+	    /* case LFT_HTTP_STATUS:
388
+	     *           out = statusline->text;
389
+	     *     quote = 1;
390
+	     *     break;
391
+	     */
392
+
393
+	case LFT_SQUID_STATUS:
394
+	    out = log_tags[al->cache.code];
395
+	    break;
396
+
397
+	    /* case LFT_SQUID_ERROR: */
398
+
399
+	case LFT_SQUID_HIERARCHY:
400
+	    if (al->hier.ping.timedout)
401
+		memBufAppend(&mb, "TIMEOUT_", 8);
402
+	    out = hier_strings[al->hier.code];
403
+	    break;
404
+
405
+	case LFT_MIME_TYPE:
406
+	    out = al->http.content_type;
407
+	    break;
408
+
409
+	case LFT_REQUEST_METHOD:
410
+	    out = al->private.method_str;
411
+	    break;
412
+
413
+	case LFT_REQUEST_URI:
414
+	    out = al->url;
415
+	    break;
416
+
417
+	case LFT_REQUEST_VERSION:
418
+	    snprintf(tmp, sizeof(tmp), "%d.%d", (int) al->http.version.major, (int) al->http.version.minor);
419
+	    out = tmp;
420
+	    break;
421
+
422
+	    /*case LFT_REQUEST_SIZE_TOTAL: */
423
+	    /*case LFT_REQUEST_SIZE_LINE: */
424
+	    /*case LFT_REQUEST_SIZE_HEADERS: */
425
+	    /*case LFT_REQUEST_SIZE_BODY: */
426
+	    /*case LFT_REQUEST_SIZE_BODY_NO_TE: */
427
+
428
+	case LFT_REPLY_SIZE_TOTAL:
429
+	    outint = al->cache.size;
430
+	    doint = 1;
431
+	    break;
432
+
433
+	    /*case LFT_REPLY_SIZE_LINE: */
434
+	    /*case LFT_REPLY_SIZE_HEADERS: */
435
+	    /*case LFT_REPLY_SIZE_BODY: */
436
+	    /*case LFT_REPLY_SIZE_BODY_NO_TE: */
437
+
438
+#ifdef HAVE_EXTACL_LOG
439
+	case LFT_EXT_LOG:
440
+	    if (al->request)
441
+		out = strBuf(al->request->extacl_log);
442
+
443
+	    quote = 1;
444
+	    break;
445
+#endif
446
+
447
+	case LFT_PERCENT:
448
+	    out = "%";
449
+	    break;
450
+	}
451
+
452
+	if (doint) {
453
+	    snprintf(tmp, sizeof(tmp), "%0*ld", fmt->zero ? (int) fmt->width : 0, outint);
454
+	    out = tmp;
455
+	}
456
+	if (out && *out) {
457
+	    if (quote || fmt->quote != LOG_QUOTE_NONE) {
458
+		char *newout = NULL;
459
+		int newfree = 0;
460
+		switch (fmt->quote) {
461
+		case LOG_QUOTE_NONE:
462
+		    newout = rfc1738_escape_unescaped(out);
463
+		    break;
464
+		case LOG_QUOTE_QUOTES:
465
+		    newout = log_quoted_string(out);
466
+		    newfree = 1;
467
+		    break;
468
+		case LOG_QUOTE_BRAKETS:
469
+		    newout = log_quote(out);
470
+		    newfree = 1;
471
+		    break;
472
+		case LOG_QUOTE_URL:
473
+		    newout = rfc1738_escape(out);
474
+		    break;
475
+		case LOG_QUOTE_RAW:
476
+		    break;
477
+		}
478
+		if (newout) {
479
+		    if (dofree)
480
+			safe_free(out);
481
+		    out = newout;
482
+		    dofree = newfree;
483
+		}
484
+	    }
485
+	    if (fmt->width) {
486
+		if (fmt->left)
487
+		    memBufPrintf(&mb, "%-*s", (int) fmt->width, out);
488
+		else
489
+		    memBufPrintf(&mb, "%*s", (int) fmt->width, out);
490
+	    } else
491
+		memBufAppend(&mb, out, strlen(out));
492
+	} else {
493
+	    memBufAppend(&mb, "-", 1);
494
+	}
495
+	if (fmt->space)
496
+	    memBufAppend(&mb, " ", 1);
497
+	stringClean(&sb);
498
+	if (dofree)
499
+	    safe_free(out);
500
+    }
501
+    logfilePrintf(logfile, "%s\n", mb.buf);
502
+}
503
+
504
+/* parses a single token. Returns the token length in characters,
505
+ * and fills in the lt item with the token information.
506
+ * def is for sure null-terminated
507
+ */
508
+static int
509
+accessLogGetNewLogFormatToken(logformat_token * lt, char *def, enum log_quote *quote)
510
+{
511
+    char *cur = def;
512
+    struct logformat_token_table_entry *lte;
513
+    int l;
514
+
515
+    memset(lt, 0, sizeof(*lt));
516
+    l = strcspn(cur, "%");
517
+    if (l > 0) {
518
+	char *cp;
519
+	/* it's a string for sure, until \0 or the next % */
520
+	cp = xmalloc(l + 1);
521
+	xstrncpy(cp, cur, l + 1);
522
+	lt->type = LFT_STRING;
523
+	lt->data.string = cp;
524
+	while (l > 0) {
525
+	    switch (*cur) {
526
+	    case '"':
527
+		if (*quote == LOG_QUOTE_NONE)
528
+		    *quote = LOG_QUOTE_QUOTES;
529
+		else if (*quote == LOG_QUOTE_QUOTES)
530
+		    *quote = LOG_QUOTE_NONE;
531
+		break;
532
+	    case '[':
533
+		if (*quote == LOG_QUOTE_NONE)
534
+		    *quote = LOG_QUOTE_BRAKETS;
535
+		break;
536
+	    case ']':
537
+		if (*quote == LOG_QUOTE_BRAKETS)
538
+		    *quote = LOG_QUOTE_NONE;
539
+		break;
540
+	    }
541
+	    cur++;
542
+	    l--;
543
+	}
544
+	goto done;
545
+    }
546
+    if (!*cur)
547
+	goto done;
548
+    cur++;
549
+    switch (*cur) {
550
+    case '"':
551
+	lt->quote = LOG_QUOTE_QUOTES;
552
+	cur++;
553
+	break;
554
+    case '\'':
555
+	lt->quote = LOG_QUOTE_RAW;
556
+	cur++;
557
+	break;
558
+    case '[':
559
+	lt->quote = LOG_QUOTE_BRAKETS;
560
+	cur++;
561
+	break;
562
+    case '#':
563
+	lt->quote = LOG_QUOTE_URL;
564
+	cur++;
565
+	break;
566
+    default:
567
+	lt->quote = *quote;
568
+	break;
569
+    }
570
+    if (*cur == '-') {
571
+	lt->left = 1;
572
+	cur++;
573
+    }
574
+    if (*cur == '0') {
575
+	lt->zero = 1;
576
+	cur++;
577
+    }
578
+    if (isdigit(*cur))
579
+	lt->width = strtol(cur, &cur, 10);
580
+    if (*cur == '.')
581
+	lt->precision = strtol(cur + 1, &cur, 10);
582
+    if (*cur == '{') {
583
+	char *cp;
584
+	cur++;
585
+	l = strcspn(cur, "}");
586
+	cp = xmalloc(l + 1);
587
+	xstrncpy(cp, cur, l + 1);
588
+	lt->data.string = cp;
589
+	cur += l;
590
+	if (*cur == '}')
591
+	    cur++;
592
+    }
593
+    lt->type = LFT_NONE;
594
+    for (lte = logformat_token_table; lte->config != NULL; lte++) {
595
+	if (strncmp(lte->config, cur, strlen(lte->config)) == 0) {
596
+	    lt->type = lte->token_type;
597
+	    cur += strlen(lte->config);
598
+	    break;
599
+	}
600
+    }
601
+    if (lt->type == LFT_NONE) {
602
+	fatalf("Can't parse configuration token: '%s'\n",
603
+	    def);
604
+    }
605
+    if (*cur == ' ') {
606
+	lt->space = 1;
607
+	cur++;
608
+    }
609
+  done:
610
+    switch (lt->type) {
611
+    case LFT_REQUEST_HEADER:
612
+    case LFT_REPLY_HEADER:
613
+	if (lt->data.string) {
614
+	    char *header = lt->data.string;
615
+	    char *cp = strchr(header, ':');
616
+	    if (cp) {
617
+		*cp++ = '\0';
618
+		if (*cp == ',' || *cp == ';' || *cp == ':')
619
+		    lt->data.header.separator = *cp++;
620
+		else
621
+		    lt->data.header.separator = ',';
622
+		lt->data.header.element = cp;
623
+		lt->type = (lt->type == LFT_REQUEST_HEADER) ?
624
+		    LFT_REQUEST_HEADER_ELEM :
625
+		    LFT_REPLY_HEADER_ELEM;
626
+	    }
627
+	    lt->data.header.header = header;
628
+	} else {
629
+	    lt->type = (lt->type == LFT_REQUEST_HEADER) ?
630
+		LFT_REQUEST_ALL_HEADERS :
631
+		LFT_REPLY_ALL_HEADERS;
632
+	    Config.onoff.log_mime_hdrs = 1;
633
+	}
634
+	break;
635
+    case LFT_CLIENT_FQDN:
636
+	Config.onoff.log_fqdn = 1;
637
+	break;
638
+    case LFT_TIME_SUBSECOND:
639
+	lt->divisor = 1000;
640
+	if (lt->precision) {
641
+	    int i;
642
+	    lt->divisor = 1000000;
643
+	    for (i = lt->precision; i > 1; i--)
644
+		lt->divisor /= 10;
645
+	    if (!lt->divisor)
646
+		lt->divisor = 0;
647
+	}
648
+	break;
649
+    default:
650
+	break;
651
+    }
652
+    return (cur - def);
653
+}
654
+
655
+int
656
+accessLogParseLogFormat(logformat_token ** fmt, char *def)
657
+{
658
+    char *cur, *eos;
659
+    logformat_token *new_lt, *last_lt;
660
+    enum log_quote quote = LOG_QUOTE_NONE;
661
+
662
+    debug(46, 1) ("accessLogParseLogFormat: got definition '%s'\n", def);
663
+
664
+    /* very inefficent parser, but who cares, this needs to be simple */
665
+    /* First off, let's tokenize, we'll optimize in a second pass.
666
+     * A token can either be a %-prefixed sequence (usually a dynamic
667
+     * token but it can be an escaped sequence), or a string. */
668
+    cur = def;
669
+    eos = def + strlen(def);
670
+    *fmt = new_lt = last_lt = xmalloc(sizeof(logformat_token));
671
+    cur += accessLogGetNewLogFormatToken(new_lt, cur, &quote);
672
+    while (cur < eos) {
673
+	new_lt = xmalloc(sizeof(logformat_token));
674
+	last_lt->next = new_lt;
675
+	last_lt = new_lt;
676
+	cur += accessLogGetNewLogFormatToken(new_lt, cur, &quote);
677
+    }
678
+    return 1;
679
+}
680
+
681
+void
682
+accessLogDumpLogFormat(StoreEntry * entry, const char *name, logformat * definitions)
683
+{
684
+    logformat_token *t;
685
+    logformat *format;
686
+    struct logformat_token_table_entry *te;
687
+    debug(46, 0) ("accessLogDumpLogFormat called\n");
688
+
689
+    for (format = definitions; format; format = format->next) {
690
+	debug(46, 0) ("Dumping logformat definition for %s\n", format->name);
691
+	storeAppendPrintf(entry, "logformat %s ", format->name);
692
+	for (t = format->format; t; t = t->next) {
693
+	    if (t->type == LFT_STRING)
694
+		storeAppendPrintf(entry, "%s", t->data.string);
695
+	    else {
696
+		char argbuf[256];
697
+		char *arg = NULL;
698
+		logformat_bcode_t type = t->type;
699
+
700
+		switch (type) {
701
+		    /* special cases */
702
+		case LFT_STRING:
703
+		    break;
704
+		case LFT_REQUEST_HEADER_ELEM:
705
+		case LFT_REPLY_HEADER_ELEM:
706
+		    if (t->data.header.separator != ',')
707
+			snprintf(argbuf, sizeof(argbuf), "%s:%c%s", t->data.header.header, t->data.header.separator, t->data.header.element);
708
+		    else
709
+			snprintf(argbuf, sizeof(argbuf), "%s:%s", t->data.header.header, t->data.header.element);
710
+
711
+		    arg = argbuf;
712
+		    type = (type == LFT_REQUEST_HEADER_ELEM) ?
713
+			LFT_REQUEST_HEADER :
714
+			LFT_REPLY_HEADER;
715
+		    break;
716
+
717
+		case LFT_REQUEST_ALL_HEADERS:
718
+		case LFT_REPLY_ALL_HEADERS:
719
+		    type = (type == LFT_REQUEST_ALL_HEADERS) ?
720
+			LFT_REQUEST_HEADER :
721
+			LFT_REPLY_HEADER;
722
+		    break;
723
+
724
+		default:
725
+		    if (t->data.string)
726
+			arg = t->data.string;
727
+		    break;
728
+		}
729
+		storeAppend(entry, "%", 1);
730
+		switch (t->quote) {
731
+		case LOG_QUOTE_QUOTES:
732
+		    storeAppend(entry, "\"", 1);
733
+		    break;
734
+		case LOG_QUOTE_BRAKETS:
735
+		    storeAppend(entry, "[", 1);
736
+		    break;
737
+		case LOG_QUOTE_URL:
738
+		    storeAppend(entry, "#", 1);
739
+		    break;
740
+		case LOG_QUOTE_RAW:
741
+		    storeAppend(entry, "'", 1);
742
+		    break;
743
+		case LOG_QUOTE_NONE:
744
+		    break;
745
+		}
746
+		if (t->left)
747
+		    storeAppend(entry, "-", 1);
748
+		if (t->zero)
749
+		    storeAppend(entry, "0", 1);
750
+		if (t->width)
751
+		    storeAppendPrintf(entry, "%d", (int) t->width);
752
+		if (t->precision)
753
+		    storeAppendPrintf(entry, ".%d", (int) t->precision);
754
+		if (arg)
755
+		    storeAppendPrintf(entry, "{%s}", arg);
756
+		for (te = logformat_token_table; te->config != NULL; te++) {
757
+		    if (te->token_type == t->type) {
758
+			storeAppendPrintf(entry, "%s", te->config);
759
+			break;
760
+		    }
761
+		}
762
+		if (t->space)
763
+		    storeAppend(entry, " ", 1);
764
+		assert(te->config != NULL);
765
+	    }
766
+	}
767
+    }
768
+    storeAppend(entry, "\n", 1);
769
+}
770
+
771
+void
772
+accessLogFreeLogFormat(logformat_token ** tokens)
773
+{
774
+    while (*tokens) {
775
+	logformat_token *token = *tokens;
776
+	*tokens = token->next;
777
+	safe_free(token->data.string);
778
+	xfree(token);
779
+    }
780
+}
781
+
782
 static void
783
-accessLogSquid(AccessLogEntry * al)
784
+accessLogSquid(AccessLogEntry * al, Logfile * logfile)
785
 {
786
     const char *client = NULL;
787
     char *user = NULL;
788
@@ -261,10 +1018,19 @@
789
 	al->hier.host,
790
 	al->http.content_type);
791
     safe_free(user);
792
+    if (Config.onoff.log_mime_hdrs) {
793
+	char *ereq = log_quote(al->headers.request);
794
+	char *erep = log_quote(al->headers.reply);
795
+	logfilePrintf(logfile, " [%s] [%s]\n", ereq, erep);
796
+	safe_free(ereq);
797
+	safe_free(erep);
798
+    } else {
799
+	logfilePrintf(logfile, "\n");
800
+    }
801
 }
802
 
803
 static void
804
-accessLogCommon(AccessLogEntry * al)
805
+accessLogCommon(AccessLogEntry * al, Logfile * logfile)
806
 {
807
     const char *client = NULL;
808
     char *user1 = NULL, *user2 = NULL;
809
@@ -288,11 +1054,21 @@
810
 	hier_strings[al->hier.code]);
811
     safe_free(user1);
812
     safe_free(user2);
813
+    if (Config.onoff.log_mime_hdrs) {
814
+	char *ereq = log_quote(al->headers.request);
815
+	char *erep = log_quote(al->headers.reply);
816
+	logfilePrintf(logfile, " [%s] [%s]\n", ereq, erep);
817
+	safe_free(ereq);
818
+	safe_free(erep);
819
+    } else {
820
+	logfilePrintf(logfile, "\n");
821
+    }
822
 }
823
 
824
 void
825
-accessLogLog(AccessLogEntry * al)
826
+accessLogLog(AccessLogEntry * al, aclCheck_t * checklist)
827
 {
828
+    customlog *log;
829
     if (LogfileStatus != LOG_ENABLE)
830
 	return;
831
     if (al->url == NULL)
832
@@ -306,20 +1082,38 @@
833
     if (al->hier.host[0] == '\0')
834
 	xstrncpy(al->hier.host, dash_str, SQUIDHOSTNAMELEN);
835
 
836
-    if (Config.onoff.common_log)
837
-	accessLogCommon(al);
838
-    else
839
-	accessLogSquid(al);
840
-    if (Config.onoff.log_mime_hdrs) {
841
-	char *ereq = log_quote(al->headers.request);
842
-	char *erep = log_quote(al->headers.reply);
843
-	logfilePrintf(logfile, " [%s] [%s]\n", ereq, erep);
844
-	safe_free(ereq);
845
-	safe_free(erep);
846
-    } else {
847
-	logfilePrintf(logfile, "\n");
848
+    for (log = Config.Log.accesslogs; log; log = log->next) {
849
+	if (checklist && log->aclList && aclMatchAclList(log->aclList, checklist) != 1)
850
+	    continue;
851
+	switch (log->type) {
852
+	case CLF_AUTO:
853
+	    if (Config.onoff.common_log)
854
+		accessLogCommon(al, log->logfile);
855
+	    else
856
+		accessLogSquid(al, log->logfile);
857
+	    break;
858
+	case CLF_SQUID:
859
+	    accessLogSquid(al, log->logfile);
860
+	    break;
861
+	case CLF_COMMON:
862
+	    accessLogCommon(al, log->logfile);
863
+	    break;
864
+	case CLF_CUSTOM:
865
+	    accessLogCustom(al, log);
866
+	    break;
867
+	case CLF_NONE:
868
+	    goto last;
869
+	default:
870
+	    fatalf("Unknown log format %d\n", log->type);
871
+	    break;
872
+	}
873
+	logfileFlush(log->logfile);
874
+	if (!checklist)
875
+	    break;
876
     }
877
-    logfileFlush(logfile);
878
+  last:
879
+    (void) 0;			/* NULL statement for label */
880
+
881
 #if MULTICAST_MISS_STREAM
882
     if (al->cache.code != LOG_TCP_MISS)
883
 	(void) 0;
884
@@ -346,12 +1140,15 @@
885
 void
886
 accessLogRotate(void)
887
 {
888
+    customlog *log;
889
 #if FORW_VIA_DB
890
     fvdbClear();
891
 #endif
892
-    if (NULL == logfile)
893
-	return;
894
-    logfileRotate(logfile);
895
+    for (log = Config.Log.accesslogs; log; log = log->next) {
896
+	if (log->logfile) {
897
+	    logfileRotate(log->logfile);
898
+	}
899
+    }
900
 #if HEADERS_LOG
901
     logfileRotate(headerslog);
902
 #endif
903
@@ -360,10 +1157,13 @@
904
 void
905
 accessLogClose(void)
906
 {
907
-    if (NULL == logfile)
908
-	return;
909
-    logfileClose(logfile);
910
-    logfile = NULL;
911
+    customlog *log;
912
+    for (log = Config.Log.accesslogs; log; log = log->next) {
913
+	if (log->logfile) {
914
+	    logfileClose(log->logfile);
915
+	    log->logfile = NULL;
916
+	}
917
+    }
918
 #if HEADERS_LOG
919
     logfileClose(headerslog);
920
     headerslog = NULL;
921
@@ -383,11 +1183,14 @@
922
 void
923
 accessLogInit(void)
924
 {
925
+    customlog *log;
926
     assert(sizeof(log_tags) == (LOG_TYPE_MAX + 1) * sizeof(char *));
927
-    if (strcasecmp(Config.Log.access, "none") == 0)
928
-	return;
929
-    logfile = logfileOpen(Config.Log.access, MAX_URL << 1, 1);
930
-    LogfileStatus = LOG_ENABLE;
931
+    for (log = Config.Log.accesslogs; log; log = log->next) {
932
+	if (log->type == CLF_NONE)
933
+	    continue;
934
+	log->logfile = logfileOpen(log->filename, MAX_URL << 1, 1);
935
+	LogfileStatus = LOG_ENABLE;
936
+    }
937
 #if HEADERS_LOG
938
     headerslog = logfileOpen("/usr/local/squid/logs/headers.log", MAX_URL << 1, 0);
939
     assert(NULL != headerslog);
940
Index: src/cache_cf.c
941
diff -u src/cache_cf.c:1.38.6.29 src/cache_cf.c:1.38.6.11.4.10
942
--- src/cache_cf.c:1.38.6.29	Wed Oct 26 19:13:24 2005
943
+++ src/cache_cf.c	Fri Mar  3 18:27:50 2006
944
@@ -60,6 +60,14 @@
945
 static void dump_cachedir_option_readonly(StoreEntry * e, const char *option, SwapDir * sd);
946
 static void parse_cachedir_option_maxsize(SwapDir * sd, const char *option, const char *value, int reconfiguring);
947
 static void dump_cachedir_option_maxsize(StoreEntry * e, const char *option, SwapDir * sd);
948
+static void parse_logformat(logformat ** logformat_definitions);
949
+static void parse_access_log(customlog ** customlog_definitions);
950
+static void dump_logformat(StoreEntry * entry, const char *name, logformat * definitions);
951
+static void dump_access_log(StoreEntry * entry, const char *name, customlog * definitions);
952
+static void free_logformat(logformat ** definitions);
953
+static void free_access_log(customlog ** definitions);
954
+
955
+
956
 static struct cache_dir_option common_cachedir_options[] =
957
 {
958
     {"read-only", parse_cachedir_option_readonly, dump_cachedir_option_readonly},
959
@@ -2625,3 +2633,144 @@
960
 	return t;
961
     }
962
 }
963
+
964
+static void
965
+parse_logformat(logformat ** logformat_definitions)
966
+{
967
+    logformat *nlf;
968
+    char *name, *def;
969
+
970
+    if ((name = strtok(NULL, w_space)) == NULL)
971
+	self_destruct();
972
+    if ((def = strtok(NULL, "\r\n")) == NULL)
973
+	self_destruct();
974
+
975
+    debug(3, 1) ("Logformat for '%s' is '%s'\n", name, def);
976
+
977
+    nlf = xcalloc(1, sizeof(logformat));
978
+    nlf->name = xstrdup(name);
979
+    if (!accessLogParseLogFormat(&nlf->format, def))
980
+	self_destruct();
981
+    nlf->next = *logformat_definitions;
982
+    *logformat_definitions = nlf;
983
+}
984
+
985
+static void
986
+parse_access_log(customlog ** logs)
987
+{
988
+    const char *filename, *logdef_name;
989
+    customlog *cl;
990
+    logformat *lf;
991
+
992
+    cl = xcalloc(1, sizeof(*cl));
993
+
994
+    if ((filename = strtok(NULL, w_space)) == NULL)
995
+	self_destruct();
996
+
997
+    if (strcmp(filename, "none") == 0) {
998
+	cl->type = CLF_NONE;
999
+	goto done;
1000
+    }
1001
+    if ((logdef_name = strtok(NULL, w_space)) == NULL)
1002
+	logdef_name = "auto";
1003
+
1004
+    debug(3, 9) ("Log definition name '%s' file '%s'\n", logdef_name, filename);
1005
+
1006
+    cl->filename = xstrdup(filename);
1007
+
1008
+    /* look for the definition pointer corresponding to this name */
1009
+    lf = Config.Log.logformats;
1010
+    while (lf != NULL) {
1011
+	debug(3, 9) ("Comparing against '%s'\n", lf->name);
1012
+	if (strcmp(lf->name, logdef_name) == 0)
1013
+	    break;
1014
+	lf = lf->next;
1015
+    }
1016
+    if (lf != NULL) {
1017
+	cl->type = CLF_CUSTOM;
1018
+	cl->logFormat = lf;
1019
+    } else if (strcmp(logdef_name, "auto") == 0) {
1020
+	cl->type = CLF_AUTO;
1021
+    } else if (strcmp(logdef_name, "squid") == 0) {
1022
+	cl->type = CLF_SQUID;
1023
+    } else if (strcmp(logdef_name, "common") == 0) {
1024
+	cl->type = CLF_COMMON;
1025
+    } else {
1026
+	debug(3, 0) ("Log format '%s' is not defined\n", logdef_name);
1027
+	self_destruct();
1028
+    }
1029
+
1030
+  done:
1031
+    aclParseAclList(&cl->aclList);
1032
+
1033
+    while (*logs)
1034
+	logs = &(*logs)->next;
1035
+    *logs = cl;
1036
+}
1037
+
1038
+static void
1039
+dump_logformat(StoreEntry * entry, const char *name, logformat * definitions)
1040
+{
1041
+    accessLogDumpLogFormat(entry, name, definitions);
1042
+}
1043
+
1044
+static void
1045
+dump_access_log(StoreEntry * entry, const char *name, customlog * logs)
1046
+{
1047
+    customlog *log;
1048
+    for (log = logs; log; log = log->next) {
1049
+	storeAppendPrintf(entry, "%s ", name);
1050
+	switch (log->type) {
1051
+	case CLF_CUSTOM:
1052
+	    storeAppendPrintf(entry, "%s %s", log->filename, log->logFormat->name);
1053
+	    break;
1054
+	case CLF_NONE:
1055
+	    storeAppendPrintf(entry, "none");
1056
+	    break;
1057
+	case CLF_SQUID:
1058
+	    storeAppendPrintf(entry, "%s squid", log->filename);
1059
+	    break;
1060
+	case CLF_COMMON:
1061
+	    storeAppendPrintf(entry, "%s squid", log->filename);
1062
+	    break;
1063
+	case CLF_AUTO:
1064
+	    if (log->aclList)
1065
+		storeAppendPrintf(entry, "%s auto", log->filename);
1066
+	    else
1067
+		storeAppendPrintf(entry, "%s", log->filename);
1068
+	    break;
1069
+	case CLF_UNKNOWN:
1070
+	    break;
1071
+	}
1072
+	if (log->aclList)
1073
+	    dump_acl_list(entry, log->aclList);
1074
+	storeAppendPrintf(entry, "\n");
1075
+    }
1076
+}
1077
+
1078
+static void
1079
+free_logformat(logformat ** definitions)
1080
+{
1081
+    while (*definitions) {
1082
+	logformat *format = *definitions;
1083
+	*definitions = format->next;
1084
+	accessLogFreeLogFormat(&format->format);
1085
+	xfree(format);
1086
+    }
1087
+}
1088
+
1089
+static void
1090
+free_access_log(customlog ** definitions)
1091
+{
1092
+    while (*definitions) {
1093
+	customlog *log = *definitions;
1094
+	*definitions = log->next;
1095
+
1096
+	log->logFormat = NULL;
1097
+	log->type = CLF_UNKNOWN;
1098
+	if (log->aclList)
1099
+	    aclDestroyAclList(&log->aclList);
1100
+	safe_free(log->filename);
1101
+	xfree(log);
1102
+    }
1103
+}
1104
Index: src/cf.data.pre
1105
diff -u src/cf.data.pre:1.49.2.86 src/cf.data.pre:1.49.2.40.2.18
1106
--- src/cf.data.pre:1.49.2.86	Sat Feb 25 19:13:57 2006
1107
+++ src/cf.data.pre	Fri Mar  3 18:27:50 2006
1108
@@ -834,16 +834,97 @@
1109
 	(hard coded at 1 MB).
1110
 DOC_END
1111
 
1112
-
1113
-NAME: cache_access_log
1114
-TYPE: string
1115
-DEFAULT: @DEFAULT_ACCESS_LOG@
1116
-LOC: Config.Log.access
1117
+NAME: logformat
1118
+TYPE: logformat
1119
+LOC: Config.Log.logformats
1120
+DEFAULT: none
1121
 DOC_START
1122
-	Logs the client request activity.  Contains an entry for
1123
-	every HTTP and ICP queries received. To disable, enter "none".
1124
-DOC_END
1125
+	Usage:
1126
+
1127
+	logformat <name> <format specification>
1128
+
1129
+	Defines an access log format.
1130
+
1131
+	The <format specification> is a string with embedded % format codes
1132
+	
1133
+	% format codes all follow the same basic structure where all but
1134
+	the formatcode is optional. Output strings are automatically escaped
1135
+	as required according to their context and the output format
1136
+	modifiers are usually not needed, but can be specified if an explicit
1137
+	output format is desired.
1138
+
1139
+		% ["|[|'|#] [-] [[0]width] [{argument}] formatcode
1140
+	
1141
+		"	output in quoted string format
1142
+		[	output in squid text log format as used by log_mime_hdrs
1143
+		#	output in URL quoted format
1144
+		'	output as-is
1145
+
1146
+		-	left aligned
1147
+		width	field width. If starting with 0 then the
1148
+			output is zero padded
1149
+		{arg}	argument such as header name etc
1150
+
1151
+	Format codes:
1152
+
1153
+		>a	Client source IP address
1154
+		>A	Client FQDN
1155
+		<A	Server IP address or peer name
1156
+		la	Local IP address (http_port)
1157
+		lp	Local port number (http_port)
1158
+		ts	Seconds since epoch
1159
+		tu	subsecond time (milliseconds)
1160
+		tl	Local time. Optional strftime format argument
1161
+			default %d/%b/%Y:%H:%M:%S %z
1162
+		tg	GMT time. Optional strftime format argument
1163
+			default %d/%b/%Y:%H:%M:%S %z
1164
+		tr	Response time (milliseconds)
1165
+		>h	Request header. Optional header name argument
1166
+			on the format header[:[separator]element]
1167
+		<h	Reply header. Optional header name argument
1168
+			as for >h
1169
+		un	User name
1170
+		ul	User login
1171
+		ui	User ident
1172
+		Hs	HTTP status code
1173
+		Ss	Squid request status (TCP_MISS etc)
1174
+		Sh	Squid hierarchy status (DEFAULT_PARENT etc)
1175
+		mt	MIME content type
1176
+		rm	Request method (GET/POST etc)
1177
+		ru	Request URL
1178
+		rv	Request protocol version
1179
+		ea	Log string returned by external acl
1180
+		<st	Reply size including HTTP headers
1181
+		%	a literal % character
1182
+
1183
+logformat squid  %ts.%03tu %6tr %>a %Ss/%03Hs %<st %rm %ru %un %Sh/%<A %mt
1184
+logformat squidmime  %ts.%03tu %6tr %>a %Ss/%03Hs %<st %rm %ru %un %Sh/%<A %mt [%>h] [%<h]
1185
+logformat common %>a %ui %un [%tl] "%rm %ru HTTP/%rv" %Hs %<st %Ss:%Sh
1186
+logformat combined %>a %ui %un [%tl] "%rm %ru HTTP/%rv" %Hs %<st "%{Referer}>h" "%{User-Agent}>h" %Ss:%Sh
1187
+DOC_END
1188
+
1189
+NAME: access_log cache_access_log
1190
+TYPE: access_log
1191
+LOC: Config.Log.accesslogs
1192
+DEFAULT: none
1193
+DOC_START
1194
+  These files log client request activities. Has a line every HTTP or
1195
+  ICP request. The format is:
1196
+  access_log <filepath> [<logformat name> [acl acl ...]]
1197
+
1198
+  Will log to the specified file using the specified format (which
1199
+  must be defined in a logformat directive) those entries which match
1200
+  ALL the acl's specified (which must be defined in acl clauses).
1201
+  If no acl is specified, all requests will be logged to this file.
1202
+  
1203
+  To disable logging of a request use the filepath "none", in which case
1204
+  a logformat name should not be specified.
1205
 
1206
+  To log the request via syslog specify a filepath of "syslog"
1207
+NOCOMMENT_START
1208
+access_log @DEFAULT_ACCESS_LOG@ squid
1209
+NOCOMMENT_END
1210
+DOC_END
1211
 
1212
 NAME: cache_log
1213
 TYPE: string
1214
@@ -2440,6 +2521,17 @@
1215
 	no limit imposed.
1216
 DOC_END
1217
 
1218
+NAME: log_access
1219
+TYPE: acl_access
1220
+LOC: Config.accessList.log
1221
+DEFAULT: none
1222
+COMMENT: allow|deny acl acl...
1223
+DOC_START
1224
+        This options allows you to control which requests gets logged
1225
+	to access.log (see cache_access_log directive). Requests denied
1226
+	for logging will also not be accounted for in performance counters.
1227
+DOC_END
1228
+
1229
 COMMENT_START
1230
  ADMINISTRATIVE PARAMETERS
1231
  -----------------------------------------------------------------------------
1232
Index: src/client_side.c
1233
diff -u src/client_side.c:1.47.2.76 src/client_side.c:1.47.2.31.2.15
1234
--- src/client_side.c:1.47.2.76	Fri Mar 10 19:16:31 2006
1235
+++ src/client_side.c	Mon Apr 24 08:22:33 2006
1236
@@ -871,14 +871,18 @@
1237
 	http->al.cache.code = http->log_type;
1238
 	http->al.cache.msec = tvSubMsec(http->start, current_time);
1239
 	if (request) {
1240
-	    Packer p;
1241
-	    MemBuf mb;
1242
-	    memBufDefInit(&mb);
1243
-	    packerToMemInit(&p, &mb);
1244
-	    httpHeaderPackInto(&request->header, &p);
1245
+	    if (Config.onoff.log_mime_hdrs) {
1246
+		Packer p;
1247
+		MemBuf mb;
1248
+		memBufDefInit(&mb);
1249
+		packerToMemInit(&p, &mb);
1250
+		httpHeaderPackInto(&request->header, &p);
1251
+		http->al.headers.request = xstrdup(mb.buf);
1252
+		packerClean(&p);
1253
+		memBufClean(&mb);
1254
+	    }
1255
 	    http->al.http.method = request->method;
1256
 	    http->al.http.version = request->http_ver;
1257
-	    http->al.headers.request = xstrdup(mb.buf);
1258
 	    http->al.hier = request->hier;
1259
 	    if (request->auth_user_request) {
1260
 		if (authenticateUserRequestUsername(request->auth_user_request))
1261
@@ -888,12 +892,17 @@
1262
 	    }
1263
 	    if (conn->rfc931[0])
1264
 		http->al.cache.rfc931 = conn->rfc931;
1265
-	    packerClean(&p);
1266
-	    memBufClean(&mb);
1267
 	}
1268
-	accessLogLog(&http->al);
1269
-	clientUpdateCounters(http);
1270
-	clientdbUpdate(conn->peer.sin_addr, http->log_type, PROTO_HTTP, http->out.size);
1271
+	http->al.request = request;
1272
+	if (!http->acl_checklist)
1273
+	    http->acl_checklist = clientAclChecklistCreate(Config.accessList.http, http);
1274
+	http->acl_checklist->reply = http->reply;
1275
+	if (!Config.accessList.log || aclCheckFast(Config.accessList.log, http->acl_checklist)) {
1276
+	    http->al.reply = http->reply;
1277
+	    accessLogLog(&http->al, http->acl_checklist);
1278
+	    clientUpdateCounters(http);
1279
+	    clientdbUpdate(conn->peer.sin_addr, http->log_type, PROTO_HTTP, http->out.size);
1280
+	}
1281
     }
1282
     if (http->acl_checklist)
1283
 	aclChecklistFree(http->acl_checklist);
1284
@@ -904,6 +913,7 @@
1285
     safe_free(http->al.headers.request);
1286
     safe_free(http->al.headers.reply);
1287
     safe_free(http->al.cache.authuser);
1288
+    http->al.request = NULL;
1289
     safe_free(http->redirect.location);
1290
     stringClean(&http->range_iter.boundary);
1291
     if ((e = http->entry)) {
1292
Index: src/icp_v2.c
1293
diff -u src/icp_v2.c:1.5 src/icp_v2.c:1.5.60.1
1294
--- src/icp_v2.c:1.5	Fri May  4 06:39:12 2001
1295
+++ src/icp_v2.c	Sat Jun 21 05:45:26 2003
1296
@@ -63,7 +63,7 @@
1297
     al.cache.size = len;
1298
     al.cache.code = logcode;
1299
     al.cache.msec = delay;
1300
-    accessLogLog(&al);
1301
+    accessLogLog(&al, NULL);
1302
 }
1303
 
1304
 void
1305
Index: src/logfile.c
1306
diff -u src/logfile.c:1.5.38.3 src/logfile.c:1.5.38.3.4.4
1307
--- src/logfile.c:1.5.38.3	Mon Jan 20 19:15:11 2003
1308
+++ src/logfile.c	Sun May 21 16:56:52 2006
1309
@@ -36,36 +36,127 @@
1310
 
1311
 static void logfileWriteWrapper(Logfile * lf, const void *buf, size_t len);
1312
 
1313
+#if HAVE_SYSLOG
1314
+typedef struct {
1315
+    const char *name;
1316
+    int value;
1317
+}syslog_symbol_t;
1318
+
1319
+static int 
1320
+syslog_ntoa(const char *s)
1321
+{
1322
+#define syslog_symbol(a) #a, a
1323
+    static syslog_symbol_t symbols[] =
1324
+    {
1325
+#ifdef LOG_AUTHPRIV
1326
+	{syslog_symbol(LOG_AUTHPRIV)},
1327
+#endif
1328
+#ifdef LOG_DAEMON
1329
+	{syslog_symbol(LOG_DAEMON)},
1330
+#endif
1331
+#ifdef LOG_LOCAL0
1332
+	{syslog_symbol(LOG_LOCAL0)},
1333
+#endif
1334
+#ifdef LOG_LOCAL1
1335
+	{syslog_symbol(LOG_LOCAL1)},
1336
+#endif
1337
+#ifdef LOG_LOCAL2
1338
+	{syslog_symbol(LOG_LOCAL2)},
1339
+#endif
1340
+#ifdef LOG_LOCAL3
1341
+	{syslog_symbol(LOG_LOCAL3)},
1342
+#endif
1343
+#ifdef LOG_LOCAL4
1344
+	{syslog_symbol(LOG_LOCAL4)},
1345
+#endif
1346
+#ifdef LOG_LOCAL5
1347
+	{syslog_symbol(LOG_LOCAL5)},
1348
+#endif
1349
+#ifdef LOG_LOCAL6
1350
+	{syslog_symbol(LOG_LOCAL6)},
1351
+#endif
1352
+#ifdef LOG_LOCAL7
1353
+	{syslog_symbol(LOG_LOCAL7)},
1354
+#endif
1355
+#ifdef LOG_USER
1356
+	{syslog_symbol(LOG_USER)},
1357
+#endif
1358
+#ifdef LOG_ERR
1359
+	{syslog_symbol(LOG_ERR)},
1360
+#endif
1361
+#ifdef LOG_WARNING
1362
+	{syslog_symbol(LOG_WARNING)},
1363
+#endif
1364
+#ifdef LOG_NOTICE
1365
+	{syslog_symbol(LOG_NOTICE)},
1366
+#endif
1367
+#ifdef LOG_INFO
1368
+	{syslog_symbol(LOG_INFO)},
1369
+#endif
1370
+#ifdef LOG_DEBUG
1371
+	{syslog_symbol(LOG_DEBUG)},
1372
+#endif
1373
+	{NULL, 0}
1374
+    };
1375
+    syslog_symbol_t *p;
1376
+
1377
+    for (p = symbols; p->name != NULL; ++p)
1378
+	if (!strcmp(s, p->name) || !strcmp(s, p->name + 4))
1379
+	    return p->value;
1380
+    return 0;
1381
+}
1382
+
1383
+#define PRIORITY_MASK (LOG_ERR | LOG_WARNING | LOG_NOTICE | LOG_INFO | LOG_DEBUG)
1384
+#endif /* HAVE_SYSLOG */
1385
+
1386
 Logfile *
1387
 logfileOpen(const char *path, size_t bufsz, int fatal_flag)
1388
 {
1389
-    int fd;
1390
-    Logfile *lf;
1391
-    fd = file_open(path, O_WRONLY | O_CREAT | O_TEXT);
1392
-    if (DISK_ERROR == fd) {
1393
-	if (ENOENT == errno && fatal_flag) {
1394
-	    fatalf("Cannot open '%s' because\n"
1395
-		"\tthe parent directory does not exist.\n"
1396
-		"\tPlease create the directory.\n", path);
1397
-	} else if (EACCES == errno && fatal_flag) {
1398
-	    fatalf("Cannot open '%s' for writing.\n"
1399
-		"\tThe parent directory must be writeable by the\n"
1400
-		"\tuser '%s', which is the cache_effective_user\n"
1401
-		"\tset in squid.conf.", path, Config.effectiveUser);
1402
-	} else {
1403
-	    debug(50, 1) ("logfileOpen: %s: %s\n", path, xstrerror());
1404
-	    return NULL;
1405
+    Logfile *lf = xcalloc(1, sizeof(*lf));
1406
+    xstrncpy(lf->path, path, MAXPATHLEN);
1407
+#if HAVE_SYSLOG
1408
+    if (strcmp(path, "syslog") == 0 || strncmp(path, "syslog:", 7) == 0) {
1409
+	lf->flags.syslog = 1;
1410
+	lf->fd = -1;
1411
+	if (path[6] != '\0') {
1412
+	    const char *priority = path + 7;
1413
+	    char *facility = strchr(priority, '|');
1414
+	    if (facility) {
1415
+		*facility++ = '\0';
1416
+		lf->syslog_priority |= syslog_ntoa(facility);
1417
+	    }
1418
+	    lf->syslog_priority |= syslog_ntoa(priority);
1419
+	}
1420
+	if ((lf->syslog_priority & PRIORITY_MASK) == 0)
1421
+	    lf->syslog_priority |= LOG_INFO;
1422
+    } else
1423
+#endif
1424
+    {
1425
+	int fd = file_open(path, O_WRONLY | O_CREAT | O_TEXT);
1426
+	if (DISK_ERROR == fd) {
1427
+	    if (ENOENT == errno && fatal_flag) {
1428
+		fatalf("Cannot open '%s' because\n"
1429
+		    "\tthe parent directory does not exist.\n"
1430
+		    "\tPlease create the directory.\n", path);
1431
+	    } else if (EACCES == errno && fatal_flag) {
1432
+		fatalf("Cannot open '%s' for writing.\n"
1433
+		    "\tThe parent directory must be writeable by the\n"
1434
+		    "\tuser '%s', which is the cache_effective_user\n"
1435
+		    "\tset in squid.conf.", path, Config.effectiveUser);
1436
+	    } else {
1437
+		debug(50, 1) ("logfileOpen: %s: %s\n", path, xstrerror());
1438
+		safe_free(lf);
1439
+		return NULL;
1440
+	    }
1441
+	}
1442
+	lf->fd = fd;
1443
+	if (bufsz > 0) {
1444
+	    lf->buf = xmalloc(bufsz);
1445
+	    lf->bufsz = bufsz;
1446
 	}
1447
     }
1448
-    lf = xcalloc(1, sizeof(*lf));
1449
-    lf->fd = fd;
1450
     if (fatal_flag)
1451
 	lf->flags.fatal = 1;
1452
-    xstrncpy(lf->path, path, MAXPATHLEN);
1453
-    if (bufsz > 0) {
1454
-	lf->buf = xmalloc(bufsz);
1455
-	lf->bufsz = bufsz;
1456
-    }
1457
     return lf;
1458
 }
1459
 
1460
@@ -73,7 +164,8 @@
1461
 logfileClose(Logfile * lf)
1462
 {
1463
     logfileFlush(lf);
1464
-    file_close(lf->fd);
1465
+    if (lf->fd >= 0)
1466
+	file_close(lf->fd);
1467
     if (lf->buf)
1468
 	xfree(lf->buf);
1469
     xfree(lf);
1470
@@ -89,6 +181,8 @@
1471
     char from[MAXPATHLEN];
1472
     char to[MAXPATHLEN];
1473
     assert(lf->path);
1474
+    if (lf->flags.syslog)
1475
+	return;
1476
 #ifdef S_ISREG
1477
     if (stat(lf->path, &sb) == 0)
1478
 	if (S_ISREG(sb.st_mode) == 0)
1479
@@ -120,6 +214,12 @@
1480
 void
1481
 logfileWrite(Logfile * lf, void *buf, size_t len)
1482
 {
1483
+#if HAVE_SYSLOG
1484
+    if (lf->flags.syslog) {
1485
+	syslog(lf->syslog_priority, "%s", (char *) buf);
1486
+	return;
1487
+    }
1488
+#endif
1489
     if (0 == lf->bufsz) {
1490
 	/* buffering disabled */
1491
 	logfileWriteWrapper(lf, buf, len);
1492
Index: src/protos.h
1493
diff -u src/protos.h:1.41.6.34 src/protos.h:1.41.6.14.2.10
1494
--- src/protos.h:1.41.6.34	Sat Feb 25 19:13:57 2006
1495
+++ src/protos.h	Fri Mar  3 18:27:52 2006
1496
@@ -34,11 +34,14 @@
1497
 #ifndef SQUID_PROTOS_H
1498
 #define SQUID_PROTOS_H
1499
 
1500
-extern void accessLogLog(AccessLogEntry *);
1501
+extern void accessLogLog(AccessLogEntry *, aclCheck_t * checklist);
1502
 extern void accessLogRotate(void);
1503
 extern void accessLogClose(void);
1504
 extern void accessLogInit(void);
1505
 extern const char *accessLogTime(time_t);
1506
+extern int accessLogParseLogFormat(logformat_token ** fmt, char *def);
1507
+extern void accessLogDumpLogFormat(StoreEntry * entry, const char *name, logformat * definitions);
1508
+extern void accessLogFreeLogFormat(logformat_token ** fmt);
1509
 extern void hierarchyNote(HierarchyLogEntry *, hier_code, const char *);
1510
 #if FORW_VIA_DB
1511
 extern void fvdbCountVia(const char *key);
1512
Index: src/structs.h
1513
diff -u src/structs.h:1.48.2.46 src/structs.h:1.48.2.11.2.14
1514
--- src/structs.h:1.48.2.46	Fri Mar 10 19:16:31 2006
1515
+++ src/structs.h	Mon Apr 24 08:22:34 2006
1516
@@ -465,7 +465,6 @@
1517
     char *as_whois_server;
1518
     struct {
1519
 	char *log;
1520
-	char *access;
1521
 	char *store;
1522
 	char *swap;
1523
 #if USE_USERAGENT_LOG
1524
@@ -477,6 +476,8 @@
1525
 #if WIP_FWD_LOG
1526
 	char *forward;
1527
 #endif
1528
+	logformat *logformats;
1529
+	customlog *accesslogs;
1530
 	int rotateNumber;
1531
     } Log;
1532
     char *adminEmail;
1533
@@ -623,6 +624,7 @@
1534
 	acl_access *AlwaysDirect;
1535
 	acl_access *ASlists;
1536
 	acl_access *noCache;
1537
+	acl_access *log;
1538
 #if SQUID_SNMP
1539
 	acl_access *snmp;
1540
 #endif
1541
@@ -1061,6 +1063,8 @@
1542
 	const char *method_str;
1543
     } private;
1544
     HierarchyLogEntry hier;
1545
+    HttpReply *reply;
1546
+    request_t *request;
1547
 };
1548
 
1549
 struct _clientHttpRequest {
1550
@@ -2210,8 +2214,32 @@
1551
     size_t bufsz;
1552
     ssize_t offset;
1553
     struct {
1554
-	unsigned int fatal:1;
1555
+	unsigned int fatal;
1556
+	unsigned int syslog;
1557
     } flags;
1558
+    int syslog_priority;
1559
+};
1560
+
1561
+struct _logformat {
1562
+    char *name;
1563
+    logformat_token *format;
1564
+    logformat *next;
1565
+};
1566
+
1567
+struct _customlog {
1568
+    char *filename;
1569
+    acl_list *aclList;
1570
+    logformat *logFormat;
1571
+    Logfile *logfile;
1572
+    customlog *next;
1573
+    enum {
1574
+	CLF_UNKNOWN,
1575
+	CLF_AUTO,
1576
+	CLF_CUSTOM,
1577
+	CLF_SQUID,
1578
+	CLF_COMMON,
1579
+	CLF_NONE
1580
+    } type;
1581
 };
1582
 
1583
 struct cache_dir_option {
1584
Index: src/typedefs.h
1585
diff -u src/typedefs.h:1.25.6.8 src/typedefs.h:1.25.6.2.2.6
1586
--- src/typedefs.h:1.25.6.8	Sat Mar 26 18:16:17 2005
1587
+++ src/typedefs.h	Thu May 26 21:34:16 2005
1588
@@ -209,6 +209,9 @@
1589
 typedef struct _storerepl_entry storerepl_entry_t;
1590
 typedef struct _diskd_queue diskd_queue;
1591
 typedef struct _Logfile Logfile;
1592
+typedef struct _logformat_token logformat_token;
1593
+typedef struct _logformat logformat;
1594
+typedef struct _customlog customlog;
1595
 typedef struct _RemovalPolicy RemovalPolicy;
1596
 typedef struct _RemovalPolicyWalker RemovalPolicyWalker;
1597
 typedef struct _RemovalPurgeWalker RemovalPurgeWalker;

Return to bug 99750