View | Details | Raw Unified | Return to bug 113155 | Differences between
and this patch

Collapse All | Expand All

(-)files/icap-2.6-core.patch (-7056 lines)
Lines 1-7056 Link Here
1
Patch 1 of 2 to integrate the icap-2_6 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.6-bootstrap.patch.
10
11
The complete 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 -rZ-icap-2_6_merge_HEAD -ricap-2_6
15
16
and manually adapted because of changes in the Squid code base.
17
18
See http://devel.squid-cache.org/icap/ for further information
19
about the ICAP client project.
20
21
Patch last updated: 2007-05-17
22
23
Note: ICAP client support for Squid-2 is no longer supported by
24
      the Squid developers. This means that even known bugs in this
25
      code will not be fixed. If you need ICAP support please try
26
      Squid-3.
27
28
Index: errors/Azerbaijani/ERR_ICAP_FAILURE
29
===================================================================
30
RCS file: errors/Azerbaijani/ERR_ICAP_FAILURE
31
diff -N errors/Azerbaijani/ERR_ICAP_FAILURE
32
--- /dev/null	1 Jan 1970 00:00:00 -0000
33
+++ errors/Azerbaijani/ERR_ICAP_FAILURE	17 May 2006 17:57:59 -0000	1.1.14.1
34
@@ -0,0 +1,31 @@
35
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
36
+<HTML><HEAD>
37
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
38
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
39
+</HEAD><BODY>
40
+<H1>ERROR</H1>
41
+<H2>The requested URL could not be retrieved</H2>
42
+<HR noshade size="1px">
43
+<P>
44
+While attempting to retrieve the URL:
45
+<A HREF="%U">%U</A>
46
+<P>
47
+the following error was encountered:
48
+<UL>
49
+<LI>
50
+<STRONG>
51
+ICAP protocol error.
52
+</STRONG>
53
+</UL>
54
+
55
+<P>
56
+<P>
57
+Some aspect of the ICAP communication failed. Possible problems:
58
+<UL>
59
+<LI>ICAP server is not reachable.
60
+<LI>Illegal response from ICAP server.
61
+</UL>
62
+</P>
63
+
64
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
65
+
66
Index: errors/Bulgarian/ERR_ICAP_FAILURE
67
===================================================================
68
RCS file: errors/Bulgarian/ERR_ICAP_FAILURE
69
diff -N errors/Bulgarian/ERR_ICAP_FAILURE
70
--- /dev/null	1 Jan 1970 00:00:00 -0000
71
+++ errors/Bulgarian/ERR_ICAP_FAILURE	17 May 2006 17:57:59 -0000	1.1.14.1
72
@@ -0,0 +1,31 @@
73
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
74
+<HTML><HEAD>
75
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
76
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
77
+</HEAD><BODY>
78
+<H1>ERROR</H1>
79
+<H2>The requested URL could not be retrieved</H2>
80
+<HR noshade size="1px">
81
+<P>
82
+While attempting to retrieve the URL:
83
+<A HREF="%U">%U</A>
84
+<P>
85
+the following error was encountered:
86
+<UL>
87
+<LI>
88
+<STRONG>
89
+ICAP protocol error.
90
+</STRONG>
91
+</UL>
92
+
93
+<P>
94
+<P>
95
+Some aspect of the ICAP communication failed. Possible problems:
96
+<UL>
97
+<LI>ICAP server is not reachable.
98
+<LI>Illegal response from ICAP server.
99
+</UL>
100
+</P>
101
+
102
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
103
+
104
Index: errors/Catalan/ERR_ICAP_FAILURE
105
===================================================================
106
RCS file: errors/Catalan/ERR_ICAP_FAILURE
107
diff -N errors/Catalan/ERR_ICAP_FAILURE
108
--- /dev/null	1 Jan 1970 00:00:00 -0000
109
+++ errors/Catalan/ERR_ICAP_FAILURE	17 May 2006 17:57:59 -0000	1.1.14.1
110
@@ -0,0 +1,31 @@
111
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
112
+<HTML><HEAD>
113
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
114
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
115
+</HEAD><BODY>
116
+<H1>ERROR</H1>
117
+<H2>The requested URL could not be retrieved</H2>
118
+<HR noshade size="1px">
119
+<P>
120
+While attempting to retrieve the URL:
121
+<A HREF="%U">%U</A>
122
+<P>
123
+the following error was encountered:
124
+<UL>
125
+<LI>
126
+<STRONG>
127
+ICAP protocol error.
128
+</STRONG>
129
+</UL>
130
+
131
+<P>
132
+<P>
133
+Some aspect of the ICAP communication failed. Possible problems:
134
+<UL>
135
+<LI>ICAP server is not reachable.
136
+<LI>Illegal response from ICAP server.
137
+</UL>
138
+</P>
139
+
140
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
141
+
142
Index: errors/Czech/ERR_ICAP_FAILURE
143
===================================================================
144
RCS file: errors/Czech/ERR_ICAP_FAILURE
145
diff -N errors/Czech/ERR_ICAP_FAILURE
146
--- /dev/null	1 Jan 1970 00:00:00 -0000
147
+++ errors/Czech/ERR_ICAP_FAILURE	17 May 2006 17:57:59 -0000	1.1.14.1
148
@@ -0,0 +1,31 @@
149
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
150
+<HTML><HEAD>
151
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
152
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
153
+</HEAD><BODY>
154
+<H1>ERROR</H1>
155
+<H2>The requested URL could not be retrieved</H2>
156
+<HR noshade size="1px">
157
+<P>
158
+While attempting to retrieve the URL:
159
+<A HREF="%U">%U</A>
160
+<P>
161
+the following error was encountered:
162
+<UL>
163
+<LI>
164
+<STRONG>
165
+ICAP protocol error.
166
+</STRONG>
167
+</UL>
168
+
169
+<P>
170
+<P>
171
+Some aspect of the ICAP communication failed. Possible problems:
172
+<UL>
173
+<LI>ICAP server is not reachable.
174
+<LI>Illegal response from ICAP server.
175
+</UL>
176
+</P>
177
+
178
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
179
+
180
Index: errors/Danish/ERR_ICAP_FAILURE
181
===================================================================
182
RCS file: errors/Danish/ERR_ICAP_FAILURE
183
diff -N errors/Danish/ERR_ICAP_FAILURE
184
--- /dev/null	1 Jan 1970 00:00:00 -0000
185
+++ errors/Danish/ERR_ICAP_FAILURE	17 May 2006 17:57:59 -0000	1.1.14.1
186
@@ -0,0 +1,31 @@
187
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
188
+<HTML><HEAD>
189
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
190
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
191
+</HEAD><BODY>
192
+<H1>ERROR</H1>
193
+<H2>The requested URL could not be retrieved</H2>
194
+<HR noshade size="1px">
195
+<P>
196
+While attempting to retrieve the URL:
197
+<A HREF="%U">%U</A>
198
+<P>
199
+the following error was encountered:
200
+<UL>
201
+<LI>
202
+<STRONG>
203
+ICAP protocol error.
204
+</STRONG>
205
+</UL>
206
+
207
+<P>
208
+<P>
209
+Some aspect of the ICAP communication failed. Possible problems:
210
+<UL>
211
+<LI>ICAP server is not reachable.
212
+<LI>Illegal response from ICAP server.
213
+</UL>
214
+</P>
215
+
216
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
217
+
218
Index: errors/Dutch/ERR_ICAP_FAILURE
219
===================================================================
220
RCS file: errors/Dutch/ERR_ICAP_FAILURE
221
diff -N errors/Dutch/ERR_ICAP_FAILURE
222
--- /dev/null	1 Jan 1970 00:00:00 -0000
223
+++ errors/Dutch/ERR_ICAP_FAILURE	17 May 2006 17:57:59 -0000	1.1.14.1
224
@@ -0,0 +1,31 @@
225
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
226
+<HTML><HEAD>
227
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
228
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
229
+</HEAD><BODY>
230
+<H1>ERROR</H1>
231
+<H2>The requested URL could not be retrieved</H2>
232
+<HR noshade size="1px">
233
+<P>
234
+While attempting to retrieve the URL:
235
+<A HREF="%U">%U</A>
236
+<P>
237
+the following error was encountered:
238
+<UL>
239
+<LI>
240
+<STRONG>
241
+ICAP protocol error.
242
+</STRONG>
243
+</UL>
244
+
245
+<P>
246
+<P>
247
+Some aspect of the ICAP communication failed. Possible problems:
248
+<UL>
249
+<LI>ICAP server is not reachable.
250
+<LI>Illegal response from ICAP server.
251
+</UL>
252
+</P>
253
+
254
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
255
+
256
Index: errors/English/ERR_ICAP_FAILURE
257
===================================================================
258
RCS file: errors/English/ERR_ICAP_FAILURE
259
diff -N errors/English/ERR_ICAP_FAILURE
260
--- /dev/null	1 Jan 1970 00:00:00 -0000
261
+++ errors/English/ERR_ICAP_FAILURE	17 May 2006 17:57:59 -0000	1.1.14.1
262
@@ -0,0 +1,31 @@
263
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
264
+<HTML><HEAD>
265
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
266
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
267
+</HEAD><BODY>
268
+<H1>ERROR</H1>
269
+<H2>The requested URL could not be retrieved</H2>
270
+<HR noshade size="1px">
271
+<P>
272
+While attempting to retrieve the URL:
273
+<A HREF="%U">%U</A>
274
+<P>
275
+the following error was encountered:
276
+<UL>
277
+<LI>
278
+<STRONG>
279
+ICAP protocol error.
280
+</STRONG>
281
+</UL>
282
+
283
+<P>
284
+<P>
285
+Some aspect of the ICAP communication failed. Possible problems:
286
+<UL>
287
+<LI>ICAP server is not reachable.
288
+<LI>Illegal response from ICAP server.
289
+</UL>
290
+</P>
291
+
292
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
293
+
294
Index: errors/Estonian/ERR_ICAP_FAILURE
295
===================================================================
296
RCS file: errors/Estonian/ERR_ICAP_FAILURE
297
diff -N errors/Estonian/ERR_ICAP_FAILURE
298
--- /dev/null	1 Jan 1970 00:00:00 -0000
299
+++ errors/Estonian/ERR_ICAP_FAILURE	17 May 2006 17:57:59 -0000	1.1.14.1
300
@@ -0,0 +1,31 @@
301
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
302
+<HTML><HEAD>
303
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
304
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
305
+</HEAD><BODY>
306
+<H1>ERROR</H1>
307
+<H2>The requested URL could not be retrieved</H2>
308
+<HR noshade size="1px">
309
+<P>
310
+While attempting to retrieve the URL:
311
+<A HREF="%U">%U</A>
312
+<P>
313
+the following error was encountered:
314
+<UL>
315
+<LI>
316
+<STRONG>
317
+ICAP protocol error.
318
+</STRONG>
319
+</UL>
320
+
321
+<P>
322
+<P>
323
+Some aspect of the ICAP communication failed. Possible problems:
324
+<UL>
325
+<LI>ICAP server is not reachable.
326
+<LI>Illegal response from ICAP server.
327
+</UL>
328
+</P>
329
+
330
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
331
+
332
Index: errors/Finnish/ERR_ICAP_FAILURE
333
===================================================================
334
RCS file: errors/Finnish/ERR_ICAP_FAILURE
335
diff -N errors/Finnish/ERR_ICAP_FAILURE
336
--- /dev/null	1 Jan 1970 00:00:00 -0000
337
+++ errors/Finnish/ERR_ICAP_FAILURE	17 May 2006 17:57:59 -0000	1.1.14.1
338
@@ -0,0 +1,31 @@
339
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
340
+<HTML><HEAD>
341
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
342
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
343
+</HEAD><BODY>
344
+<H1>ERROR</H1>
345
+<H2>The requested URL could not be retrieved</H2>
346
+<HR noshade size="1px">
347
+<P>
348
+While attempting to retrieve the URL:
349
+<A HREF="%U">%U</A>
350
+<P>
351
+the following error was encountered:
352
+<UL>
353
+<LI>
354
+<STRONG>
355
+ICAP protocol error.
356
+</STRONG>
357
+</UL>
358
+
359
+<P>
360
+<P>
361
+Some aspect of the ICAP communication failed. Possible problems:
362
+<UL>
363
+<LI>ICAP server is not reachable.
364
+<LI>Illegal response from ICAP server.
365
+</UL>
366
+</P>
367
+
368
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
369
+
370
Index: errors/French/ERR_ICAP_FAILURE
371
===================================================================
372
RCS file: errors/French/ERR_ICAP_FAILURE
373
diff -N errors/French/ERR_ICAP_FAILURE
374
--- /dev/null	1 Jan 1970 00:00:00 -0000
375
+++ errors/French/ERR_ICAP_FAILURE	17 May 2006 17:57:59 -0000	1.1.14.1
376
@@ -0,0 +1,31 @@
377
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
378
+<HTML><HEAD>
379
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
380
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
381
+</HEAD><BODY>
382
+<H1>ERROR</H1>
383
+<H2>The requested URL could not be retrieved</H2>
384
+<HR noshade size="1px">
385
+<P>
386
+While attempting to retrieve the URL:
387
+<A HREF="%U">%U</A>
388
+<P>
389
+the following error was encountered:
390
+<UL>
391
+<LI>
392
+<STRONG>
393
+ICAP protocol error.
394
+</STRONG>
395
+</UL>
396
+
397
+<P>
398
+<P>
399
+Some aspect of the ICAP communication failed. Possible problems:
400
+<UL>
401
+<LI>ICAP server is not reachable.
402
+<LI>Illegal response from ICAP server.
403
+</UL>
404
+</P>
405
+
406
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
407
+
408
Index: errors/German/ERR_ICAP_FAILURE
409
===================================================================
410
RCS file: errors/German/ERR_ICAP_FAILURE
411
diff -N errors/German/ERR_ICAP_FAILURE
412
--- /dev/null	1 Jan 1970 00:00:00 -0000
413
+++ errors/German/ERR_ICAP_FAILURE	17 May 2006 17:57:59 -0000	1.1.14.1
414
@@ -0,0 +1,33 @@
415
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
416
+<HTML><HEAD>
417
+<TITLE>FEHLER: Der angeforderte URL konnte nicht geholt werden</TITLE>
418
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
419
+</HEAD><BODY>
420
+<H1>FEHLER</H1>
421
+<H2>Der angeforderte URL konnte nicht geholt werden</H2>
422
+<HR noshade size="1px">
423
+<P>
424
+W&auml;hrend des Versuches, den URL<BR>
425
+<A HREF="%U">%U</A>
426
+
427
+<BR>
428
+zu laden, trat der folgende Fehler auf:
429
+<UL>
430
+<LI>
431
+<STRONG>
432
+ICAP-Protokollfehler
433
+</STRONG>
434
+</UL>
435
+
436
+<P>
437
+<P>
438
+Es trat ein Problem bei der ICAP-Kommunikation auf. M&ouml;gliche Gr&uuml;nde:
439
+<UL>
440
+<LI>Nicht erreichbarer ICAP-Server
441
+<LI>Ung&uuml;ltige Antwort vom ICAP-Server
442
+
443
+</UL>
444
+</P>
445
+
446
+<P>Ihr Cache Administrator ist <A HREF="mailto:%w">%w</A>. 
447
+
448
Index: errors/Greek/ERR_ICAP_FAILURE
449
===================================================================
450
RCS file: errors/Greek/ERR_ICAP_FAILURE
451
diff -N errors/Greek/ERR_ICAP_FAILURE
452
--- /dev/null	1 Jan 1970 00:00:00 -0000
453
+++ errors/Greek/ERR_ICAP_FAILURE	17 May 2006 17:57:59 -0000	1.1.12.1
454
@@ -0,0 +1,31 @@
455
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
456
+<HTML><HEAD>
457
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
458
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
459
+</HEAD><BODY>
460
+<H1>ERROR</H1>
461
+<H2>The requested URL could not be retrieved</H2>
462
+<HR noshade size="1px">
463
+<P>
464
+While attempting to retrieve the URL:
465
+<A HREF="%U">%U</A>
466
+<P>
467
+the following error was encountered:
468
+<UL>
469
+<LI>
470
+<STRONG>
471
+ICAP protocol error.
472
+</STRONG>
473
+</UL>
474
+
475
+<P>
476
+<P>
477
+Some aspect of the ICAP communication failed. Possible problems:
478
+<UL>
479
+<LI>ICAP server is not reachable.
480
+<LI>Illegal response from ICAP server.
481
+</UL>
482
+</P>
483
+
484
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
485
+
486
Index: errors/Hebrew/ERR_ICAP_FAILURE
487
===================================================================
488
RCS file: errors/Hebrew/ERR_ICAP_FAILURE
489
diff -N errors/Hebrew/ERR_ICAP_FAILURE
490
--- /dev/null	1 Jan 1970 00:00:00 -0000
491
+++ errors/Hebrew/ERR_ICAP_FAILURE	17 May 2006 17:57:59 -0000	1.1.14.1
492
@@ -0,0 +1,31 @@
493
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
494
+<HTML><HEAD>
495
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
496
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
497
+</HEAD><BODY>
498
+<H1>ERROR</H1>
499
+<H2>The requested URL could not be retrieved</H2>
500
+<HR noshade size="1px">
501
+<P>
502
+While attempting to retrieve the URL:
503
+<A HREF="%U">%U</A>
504
+<P>
505
+the following error was encountered:
506
+<UL>
507
+<LI>
508
+<STRONG>
509
+ICAP protocol error.
510
+</STRONG>
511
+</UL>
512
+
513
+<P>
514
+<P>
515
+Some aspect of the ICAP communication failed. Possible problems:
516
+<UL>
517
+<LI>ICAP server is not reachable.
518
+<LI>Illegal response from ICAP server.
519
+</UL>
520
+</P>
521
+
522
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
523
+
524
Index: errors/Hungarian/ERR_ICAP_FAILURE
525
===================================================================
526
RCS file: errors/Hungarian/ERR_ICAP_FAILURE
527
diff -N errors/Hungarian/ERR_ICAP_FAILURE
528
--- /dev/null	1 Jan 1970 00:00:00 -0000
529
+++ errors/Hungarian/ERR_ICAP_FAILURE	17 May 2006 17:57:59 -0000	1.1.14.1
530
@@ -0,0 +1,31 @@
531
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
532
+<HTML><HEAD>
533
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
534
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
535
+</HEAD><BODY>
536
+<H1>ERROR</H1>
537
+<H2>The requested URL could not be retrieved</H2>
538
+<HR noshade size="1px">
539
+<P>
540
+While attempting to retrieve the URL:
541
+<A HREF="%U">%U</A>
542
+<P>
543
+the following error was encountered:
544
+<UL>
545
+<LI>
546
+<STRONG>
547
+ICAP protocol error.
548
+</STRONG>
549
+</UL>
550
+
551
+<P>
552
+<P>
553
+Some aspect of the ICAP communication failed. Possible problems:
554
+<UL>
555
+<LI>ICAP server is not reachable.
556
+<LI>Illegal response from ICAP server.
557
+</UL>
558
+</P>
559
+
560
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
561
+
562
Index: errors/Italian/ERR_ICAP_FAILURE
563
===================================================================
564
RCS file: errors/Italian/ERR_ICAP_FAILURE
565
diff -N errors/Italian/ERR_ICAP_FAILURE
566
--- /dev/null	1 Jan 1970 00:00:00 -0000
567
+++ errors/Italian/ERR_ICAP_FAILURE	17 May 2006 17:57:59 -0000	1.1.14.1
568
@@ -0,0 +1,31 @@
569
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
570
+<HTML><HEAD>
571
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
572
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
573
+</HEAD><BODY>
574
+<H1>ERROR</H1>
575
+<H2>The requested URL could not be retrieved</H2>
576
+<HR noshade size="1px">
577
+<P>
578
+While attempting to retrieve the URL:
579
+<A HREF="%U">%U</A>
580
+<P>
581
+the following error was encountered:
582
+<UL>
583
+<LI>
584
+<STRONG>
585
+ICAP protocol error.
586
+</STRONG>
587
+</UL>
588
+
589
+<P>
590
+<P>
591
+Some aspect of the ICAP communication failed. Possible problems:
592
+<UL>
593
+<LI>ICAP server is not reachable.
594
+<LI>Illegal response from ICAP server.
595
+</UL>
596
+</P>
597
+
598
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
599
+
600
Index: errors/Japanese/ERR_ICAP_FAILURE
601
===================================================================
602
RCS file: errors/Japanese/ERR_ICAP_FAILURE
603
diff -N errors/Japanese/ERR_ICAP_FAILURE
604
--- /dev/null	1 Jan 1970 00:00:00 -0000
605
+++ errors/Japanese/ERR_ICAP_FAILURE	17 May 2006 17:57:59 -0000	1.1.14.1
606
@@ -0,0 +1,31 @@
607
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
608
+<HTML><HEAD>
609
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
610
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
611
+</HEAD><BODY>
612
+<H1>ERROR</H1>
613
+<H2>The requested URL could not be retrieved</H2>
614
+<HR noshade size="1px">
615
+<P>
616
+While attempting to retrieve the URL:
617
+<A HREF="%U">%U</A>
618
+<P>
619
+the following error was encountered:
620
+<UL>
621
+<LI>
622
+<STRONG>
623
+ICAP protocol error.
624
+</STRONG>
625
+</UL>
626
+
627
+<P>
628
+<P>
629
+Some aspect of the ICAP communication failed. Possible problems:
630
+<UL>
631
+<LI>ICAP server is not reachable.
632
+<LI>Illegal response from ICAP server.
633
+</UL>
634
+</P>
635
+
636
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
637
+
638
Index: errors/Korean/ERR_ICAP_FAILURE
639
===================================================================
640
RCS file: errors/Korean/ERR_ICAP_FAILURE
641
diff -N errors/Korean/ERR_ICAP_FAILURE
642
--- /dev/null	1 Jan 1970 00:00:00 -0000
643
+++ errors/Korean/ERR_ICAP_FAILURE	17 May 2006 17:58:00 -0000	1.1.14.1
644
@@ -0,0 +1,31 @@
645
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
646
+<HTML><HEAD>
647
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
648
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
649
+</HEAD><BODY>
650
+<H1>ERROR</H1>
651
+<H2>The requested URL could not be retrieved</H2>
652
+<HR noshade size="1px">
653
+<P>
654
+While attempting to retrieve the URL:
655
+<A HREF="%U">%U</A>
656
+<P>
657
+the following error was encountered:
658
+<UL>
659
+<LI>
660
+<STRONG>
661
+ICAP protocol error.
662
+</STRONG>
663
+</UL>
664
+
665
+<P>
666
+<P>
667
+Some aspect of the ICAP communication failed. Possible problems:
668
+<UL>
669
+<LI>ICAP server is not reachable.
670
+<LI>Illegal response from ICAP server.
671
+</UL>
672
+</P>
673
+
674
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
675
+
676
Index: errors/Lithuanian/ERR_ICAP_FAILURE
677
===================================================================
678
RCS file: errors/Lithuanian/ERR_ICAP_FAILURE
679
diff -N errors/Lithuanian/ERR_ICAP_FAILURE
680
--- /dev/null	1 Jan 1970 00:00:00 -0000
681
+++ errors/Lithuanian/ERR_ICAP_FAILURE	17 May 2006 17:58:00 -0000	1.1.14.1
682
@@ -0,0 +1,31 @@
683
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
684
+<HTML><HEAD>
685
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
686
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
687
+</HEAD><BODY>
688
+<H1>ERROR</H1>
689
+<H2>The requested URL could not be retrieved</H2>
690
+<HR noshade size="1px">
691
+<P>
692
+While attempting to retrieve the URL:
693
+<A HREF="%U">%U</A>
694
+<P>
695
+the following error was encountered:
696
+<UL>
697
+<LI>
698
+<STRONG>
699
+ICAP protocol error.
700
+</STRONG>
701
+</UL>
702
+
703
+<P>
704
+<P>
705
+Some aspect of the ICAP communication failed. Possible problems:
706
+<UL>
707
+<LI>ICAP server is not reachable.
708
+<LI>Illegal response from ICAP server.
709
+</UL>
710
+</P>
711
+
712
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
713
+
714
Index: errors/Polish/ERR_ICAP_FAILURE
715
===================================================================
716
RCS file: errors/Polish/ERR_ICAP_FAILURE
717
diff -N errors/Polish/ERR_ICAP_FAILURE
718
--- /dev/null	1 Jan 1970 00:00:00 -0000
719
+++ errors/Polish/ERR_ICAP_FAILURE	17 May 2006 17:58:00 -0000	1.1.14.1
720
@@ -0,0 +1,31 @@
721
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
722
+<HTML><HEAD>
723
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
724
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
725
+</HEAD><BODY>
726
+<H1>ERROR</H1>
727
+<H2>The requested URL could not be retrieved</H2>
728
+<HR noshade size="1px">
729
+<P>
730
+While attempting to retrieve the URL:
731
+<A HREF="%U">%U</A>
732
+<P>
733
+the following error was encountered:
734
+<UL>
735
+<LI>
736
+<STRONG>
737
+ICAP protocol error.
738
+</STRONG>
739
+</UL>
740
+
741
+<P>
742
+<P>
743
+Some aspect of the ICAP communication failed. Possible problems:
744
+<UL>
745
+<LI>ICAP server is not reachable.
746
+<LI>Illegal response from ICAP server.
747
+</UL>
748
+</P>
749
+
750
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
751
+
752
Index: errors/Portuguese/ERR_ICAP_FAILURE
753
===================================================================
754
RCS file: errors/Portuguese/ERR_ICAP_FAILURE
755
diff -N errors/Portuguese/ERR_ICAP_FAILURE
756
--- /dev/null	1 Jan 1970 00:00:00 -0000
757
+++ errors/Portuguese/ERR_ICAP_FAILURE	17 May 2006 17:58:00 -0000	1.1.14.1
758
@@ -0,0 +1,31 @@
759
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
760
+<HTML><HEAD>
761
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
762
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
763
+</HEAD><BODY>
764
+<H1>ERROR</H1>
765
+<H2>The requested URL could not be retrieved</H2>
766
+<HR noshade size="1px">
767
+<P>
768
+While attempting to retrieve the URL:
769
+<A HREF="%U">%U</A>
770
+<P>
771
+the following error was encountered:
772
+<UL>
773
+<LI>
774
+<STRONG>
775
+ICAP protocol error.
776
+</STRONG>
777
+</UL>
778
+
779
+<P>
780
+<P>
781
+Some aspect of the ICAP communication failed. Possible problems:
782
+<UL>
783
+<LI>ICAP server is not reachable.
784
+<LI>Illegal response from ICAP server.
785
+</UL>
786
+</P>
787
+
788
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
789
+
790
Index: errors/Romanian/ERR_ICAP_FAILURE
791
===================================================================
792
RCS file: errors/Romanian/ERR_ICAP_FAILURE
793
diff -N errors/Romanian/ERR_ICAP_FAILURE
794
--- /dev/null	1 Jan 1970 00:00:00 -0000
795
+++ errors/Romanian/ERR_ICAP_FAILURE	17 May 2006 17:58:00 -0000	1.1.14.1
796
@@ -0,0 +1,31 @@
797
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
798
+<HTML><HEAD>
799
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
800
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
801
+</HEAD><BODY>
802
+<H1>ERROR</H1>
803
+<H2>The requested URL could not be retrieved</H2>
804
+<HR noshade size="1px">
805
+<P>
806
+While attempting to retrieve the URL:
807
+<A HREF="%U">%U</A>
808
+<P>
809
+the following error was encountered:
810
+<UL>
811
+<LI>
812
+<STRONG>
813
+ICAP protocol error.
814
+</STRONG>
815
+</UL>
816
+
817
+<P>
818
+<P>
819
+Some aspect of the ICAP communication failed. Possible problems:
820
+<UL>
821
+<LI>ICAP server is not reachable.
822
+<LI>Illegal response from ICAP server.
823
+</UL>
824
+</P>
825
+
826
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
827
+
828
Index: errors/Russian-1251/ERR_ICAP_FAILURE
829
===================================================================
830
RCS file: errors/Russian-1251/ERR_ICAP_FAILURE
831
diff -N errors/Russian-1251/ERR_ICAP_FAILURE
832
--- /dev/null	1 Jan 1970 00:00:00 -0000
833
+++ errors/Russian-1251/ERR_ICAP_FAILURE	17 May 2006 17:58:00 -0000	1.1.14.1
834
@@ -0,0 +1,31 @@
835
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
836
+<HTML><HEAD>
837
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
838
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
839
+</HEAD><BODY>
840
+<H1>ERROR</H1>
841
+<H2>The requested URL could not be retrieved</H2>
842
+<HR noshade size="1px">
843
+<P>
844
+While attempting to retrieve the URL:
845
+<A HREF="%U">%U</A>
846
+<P>
847
+the following error was encountered:
848
+<UL>
849
+<LI>
850
+<STRONG>
851
+ICAP protocol error.
852
+</STRONG>
853
+</UL>
854
+
855
+<P>
856
+<P>
857
+Some aspect of the ICAP communication failed. Possible problems:
858
+<UL>
859
+<LI>ICAP server is not reachable.
860
+<LI>Illegal response from ICAP server.
861
+</UL>
862
+</P>
863
+
864
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
865
+
866
Index: errors/Russian-koi8-r/ERR_ICAP_FAILURE
867
===================================================================
868
RCS file: errors/Russian-koi8-r/ERR_ICAP_FAILURE
869
diff -N errors/Russian-koi8-r/ERR_ICAP_FAILURE
870
--- /dev/null	1 Jan 1970 00:00:00 -0000
871
+++ errors/Russian-koi8-r/ERR_ICAP_FAILURE	17 May 2006 17:58:00 -0000	1.1.14.1
872
@@ -0,0 +1,31 @@
873
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
874
+<HTML><HEAD>
875
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
876
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
877
+</HEAD><BODY>
878
+<H1>ERROR</H1>
879
+<H2>The requested URL could not be retrieved</H2>
880
+<HR noshade size="1px">
881
+<P>
882
+While attempting to retrieve the URL:
883
+<A HREF="%U">%U</A>
884
+<P>
885
+the following error was encountered:
886
+<UL>
887
+<LI>
888
+<STRONG>
889
+ICAP protocol error.
890
+</STRONG>
891
+</UL>
892
+
893
+<P>
894
+<P>
895
+Some aspect of the ICAP communication failed. Possible problems:
896
+<UL>
897
+<LI>ICAP server is not reachable.
898
+<LI>Illegal response from ICAP server.
899
+</UL>
900
+</P>
901
+
902
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
903
+
904
Index: errors/Serbian/ERR_ICAP_FAILURE
905
===================================================================
906
RCS file: errors/Serbian/ERR_ICAP_FAILURE
907
diff -N errors/Serbian/ERR_ICAP_FAILURE
908
--- /dev/null	1 Jan 1970 00:00:00 -0000
909
+++ errors/Serbian/ERR_ICAP_FAILURE	17 May 2006 17:58:00 -0000	1.1.14.1
910
@@ -0,0 +1,31 @@
911
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
912
+<HTML><HEAD>
913
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
914
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
915
+</HEAD><BODY>
916
+<H1>ERROR</H1>
917
+<H2>The requested URL could not be retrieved</H2>
918
+<HR noshade size="1px">
919
+<P>
920
+While attempting to retrieve the URL:
921
+<A HREF="%U">%U</A>
922
+<P>
923
+the following error was encountered:
924
+<UL>
925
+<LI>
926
+<STRONG>
927
+ICAP protocol error.
928
+</STRONG>
929
+</UL>
930
+
931
+<P>
932
+<P>
933
+Some aspect of the ICAP communication failed. Possible problems:
934
+<UL>
935
+<LI>ICAP server is not reachable.
936
+<LI>Illegal response from ICAP server.
937
+</UL>
938
+</P>
939
+
940
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
941
+
942
Index: errors/Simplify_Chinese/ERR_ICAP_FAILURE
943
===================================================================
944
RCS file: errors/Simplify_Chinese/ERR_ICAP_FAILURE
945
diff -N errors/Simplify_Chinese/ERR_ICAP_FAILURE
946
--- /dev/null	1 Jan 1970 00:00:00 -0000
947
+++ errors/Simplify_Chinese/ERR_ICAP_FAILURE	17 May 2006 17:58:00 -0000	1.1.14.1
948
@@ -0,0 +1,31 @@
949
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
950
+<HTML><HEAD>
951
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
952
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
953
+</HEAD><BODY>
954
+<H1>ERROR</H1>
955
+<H2>The requested URL could not be retrieved</H2>
956
+<HR noshade size="1px">
957
+<P>
958
+While attempting to retrieve the URL:
959
+<A HREF="%U">%U</A>
960
+<P>
961
+the following error was encountered:
962
+<UL>
963
+<LI>
964
+<STRONG>
965
+ICAP protocol error.
966
+</STRONG>
967
+</UL>
968
+
969
+<P>
970
+<P>
971
+Some aspect of the ICAP communication failed. Possible problems:
972
+<UL>
973
+<LI>ICAP server is not reachable.
974
+<LI>Illegal response from ICAP server.
975
+</UL>
976
+</P>
977
+
978
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
979
+
980
Index: errors/Slovak/ERR_ICAP_FAILURE
981
===================================================================
982
RCS file: errors/Slovak/ERR_ICAP_FAILURE
983
diff -N errors/Slovak/ERR_ICAP_FAILURE
984
--- /dev/null	1 Jan 1970 00:00:00 -0000
985
+++ errors/Slovak/ERR_ICAP_FAILURE	17 May 2006 17:58:00 -0000	1.1.14.1
986
@@ -0,0 +1,31 @@
987
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
988
+<HTML><HEAD>
989
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
990
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
991
+</HEAD><BODY>
992
+<H1>ERROR</H1>
993
+<H2>The requested URL could not be retrieved</H2>
994
+<HR noshade size="1px">
995
+<P>
996
+While attempting to retrieve the URL:
997
+<A HREF="%U">%U</A>
998
+<P>
999
+the following error was encountered:
1000
+<UL>
1001
+<LI>
1002
+<STRONG>
1003
+ICAP protocol error.
1004
+</STRONG>
1005
+</UL>
1006
+
1007
+<P>
1008
+<P>
1009
+Some aspect of the ICAP communication failed. Possible problems:
1010
+<UL>
1011
+<LI>ICAP server is not reachable.
1012
+<LI>Illegal response from ICAP server.
1013
+</UL>
1014
+</P>
1015
+
1016
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
1017
+
1018
Index: errors/Spanish/ERR_ICAP_FAILURE
1019
===================================================================
1020
RCS file: errors/Spanish/ERR_ICAP_FAILURE
1021
diff -N errors/Spanish/ERR_ICAP_FAILURE
1022
--- /dev/null	1 Jan 1970 00:00:00 -0000
1023
+++ errors/Spanish/ERR_ICAP_FAILURE	17 May 2006 17:58:00 -0000	1.1.14.1
1024
@@ -0,0 +1,31 @@
1025
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
1026
+<HTML><HEAD>
1027
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
1028
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
1029
+</HEAD><BODY>
1030
+<H1>ERROR</H1>
1031
+<H2>The requested URL could not be retrieved</H2>
1032
+<HR noshade size="1px">
1033
+<P>
1034
+While attempting to retrieve the URL:
1035
+<A HREF="%U">%U</A>
1036
+<P>
1037
+the following error was encountered:
1038
+<UL>
1039
+<LI>
1040
+<STRONG>
1041
+ICAP protocol error.
1042
+</STRONG>
1043
+</UL>
1044
+
1045
+<P>
1046
+<P>
1047
+Some aspect of the ICAP communication failed. Possible problems:
1048
+<UL>
1049
+<LI>ICAP server is not reachable.
1050
+<LI>Illegal response from ICAP server.
1051
+</UL>
1052
+</P>
1053
+
1054
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
1055
+
1056
Index: errors/Swedish/ERR_ICAP_FAILURE
1057
===================================================================
1058
RCS file: errors/Swedish/ERR_ICAP_FAILURE
1059
diff -N errors/Swedish/ERR_ICAP_FAILURE
1060
--- /dev/null	1 Jan 1970 00:00:00 -0000
1061
+++ errors/Swedish/ERR_ICAP_FAILURE	17 May 2006 17:58:00 -0000	1.1.14.1
1062
@@ -0,0 +1,31 @@
1063
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
1064
+<HTML><HEAD>
1065
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
1066
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
1067
+</HEAD><BODY>
1068
+<H1>ERROR</H1>
1069
+<H2>The requested URL could not be retrieved</H2>
1070
+<HR noshade size="1px">
1071
+<P>
1072
+While attempting to retrieve the URL:
1073
+<A HREF="%U">%U</A>
1074
+<P>
1075
+the following error was encountered:
1076
+<UL>
1077
+<LI>
1078
+<STRONG>
1079
+ICAP protocol error.
1080
+</STRONG>
1081
+</UL>
1082
+
1083
+<P>
1084
+<P>
1085
+Some aspect of the ICAP communication failed. Possible problems:
1086
+<UL>
1087
+<LI>ICAP server is not reachable.
1088
+<LI>Illegal response from ICAP server.
1089
+</UL>
1090
+</P>
1091
+
1092
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
1093
+
1094
Index: errors/Traditional_Chinese/ERR_ICAP_FAILURE
1095
===================================================================
1096
RCS file: errors/Traditional_Chinese/ERR_ICAP_FAILURE
1097
diff -N errors/Traditional_Chinese/ERR_ICAP_FAILURE
1098
--- /dev/null	1 Jan 1970 00:00:00 -0000
1099
+++ errors/Traditional_Chinese/ERR_ICAP_FAILURE	17 May 2006 17:58:00 -0000	1.1.14.1
1100
@@ -0,0 +1,31 @@
1101
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
1102
+<HTML><HEAD>
1103
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
1104
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
1105
+</HEAD><BODY>
1106
+<H1>ERROR</H1>
1107
+<H2>The requested URL could not be retrieved</H2>
1108
+<HR noshade size="1px">
1109
+<P>
1110
+While attempting to retrieve the URL:
1111
+<A HREF="%U">%U</A>
1112
+<P>
1113
+the following error was encountered:
1114
+<UL>
1115
+<LI>
1116
+<STRONG>
1117
+ICAP protocol error.
1118
+</STRONG>
1119
+</UL>
1120
+
1121
+<P>
1122
+<P>
1123
+Some aspect of the ICAP communication failed. Possible problems:
1124
+<UL>
1125
+<LI>ICAP server is not reachable.
1126
+<LI>Illegal response from ICAP server.
1127
+</UL>
1128
+</P>
1129
+
1130
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
1131
+
1132
Index: errors/Turkish/ERR_ICAP_FAILURE
1133
===================================================================
1134
RCS file: errors/Turkish/ERR_ICAP_FAILURE
1135
diff -N errors/Turkish/ERR_ICAP_FAILURE
1136
--- /dev/null	1 Jan 1970 00:00:00 -0000
1137
+++ errors/Turkish/ERR_ICAP_FAILURE	17 May 2006 17:58:00 -0000	1.1.14.1
1138
@@ -0,0 +1,31 @@
1139
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
1140
+<HTML><HEAD>
1141
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
1142
+<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
1143
+</HEAD><BODY>
1144
+<H1>ERROR</H1>
1145
+<H2>The requested URL could not be retrieved</H2>
1146
+<HR noshade size="1px">
1147
+<P>
1148
+While attempting to retrieve the URL:
1149
+<A HREF="%U">%U</A>
1150
+<P>
1151
+the following error was encountered:
1152
+<UL>
1153
+<LI>
1154
+<STRONG>
1155
+ICAP protocol error.
1156
+</STRONG>
1157
+</UL>
1158
+
1159
+<P>
1160
+<P>
1161
+Some aspect of the ICAP communication failed. Possible problems:
1162
+<UL>
1163
+<LI>ICAP server is not reachable.
1164
+<LI>Illegal response from ICAP server.
1165
+</UL>
1166
+</P>
1167
+
1168
+<P>Your cache administrator is <A HREF="mailto:%w">%w</A>. 
1169
+
1170
Index: include/util.h
1171
===================================================================
1172
RCS file: /cvsroot/squid/squid/include/util.h,v
1173
retrieving revision 1.17
1174
retrieving revision 1.13.8.3
1175
diff -p -u -b -r1.17 -r1.13.8.3
1176
--- include/util.h	10 Dec 2006 13:56:25 -0000	1.17
1177
+++ include/util.h	12 Dec 2006 22:49:41 -0000	1.13.8.3
1178
@@ -157,4 +157,12 @@ extern void WIN32_maperror(unsigned long
1179
 extern int WIN32_Close_FD_Socket(int);
1180
 #endif
1181
 
1182
+#ifndef HAVE_STRNSTR
1183
+extern char *strnstr(const char *haystack, const char *needle, size_t haystacklen);
1184
+#endif
1185
+
1186
+#ifndef HAVE_STRCASESTR
1187
+extern char *strcasestr(const char *haystack, const char *needle);
1188
+#endif
1189
+
1190
 #endif /* SQUID_UTIL_H */
1191
Index: lib/strcasestr.c
1192
===================================================================
1193
RCS file: lib/strcasestr.c
1194
diff -N lib/strcasestr.c
1195
--- /dev/null	1 Jan 1970 00:00:00 -0000
1196
+++ lib/strcasestr.c	17 May 2006 17:58:00 -0000	1.1.14.1
1197
@@ -0,0 +1,126 @@
1198
+/* Return the offset of one string within another.
1199
+   Copyright (C) 1994,1996,1997,1998,1999,2000 Free Software Foundation, Inc.
1200
+   This file is part of the GNU C Library.
1201
+
1202
+   The GNU C Library is free software; you can redistribute it and/or
1203
+   modify it under the terms of the GNU Lesser General Public
1204
+   License as published by the Free Software Foundation; either
1205
+   version 2.1 of the License, or (at your option) any later version.
1206
+
1207
+   The GNU C Library is distributed in the hope that it will be useful,
1208
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
1209
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1210
+   Lesser General Public License for more details.
1211
+
1212
+   You should have received a copy of the GNU Lesser General Public
1213
+   License along with the GNU C Library; if not, write to the Free
1214
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
1215
+   02111-1307 USA.  */
1216
+
1217
+/*
1218
+ * My personal strstr() implementation that beats most other algorithms.
1219
+ * Until someone tells me otherwise, I assume that this is the
1220
+ * fastest implementation of strstr() in C.
1221
+ * I deliberately chose not to comment it.  You should have at least
1222
+ * as much fun trying to understand it, as I had to write it :-).
1223
+ *
1224
+ * Stephen R. van den Berg, berg@pool.informatik.rwth-aachen.de	*/
1225
+
1226
+/* 
1227
+ * modified to work outside of glibc (rhorstmann, 06/04/2004)
1228
+ */
1229
+
1230
+#include "config.h"
1231
+#ifndef  HAVE_STRCASESTR
1232
+#include <ctype.h>
1233
+
1234
+typedef unsigned chartype;
1235
+
1236
+char *
1237
+strcasestr (phaystack, pneedle)
1238
+     const char *phaystack;
1239
+     const char *pneedle;
1240
+{
1241
+  register const unsigned char *haystack, *needle;
1242
+  register chartype b, c;
1243
+
1244
+  haystack = (const unsigned char *) phaystack;
1245
+  needle = (const unsigned char *) pneedle;
1246
+
1247
+  b = tolower (*needle);
1248
+  if (b != '\0')
1249
+    {
1250
+      haystack--;				/* possible ANSI violation */
1251
+      do
1252
+	{
1253
+	  c = *++haystack;
1254
+	  if (c == '\0')
1255
+	    goto ret0;
1256
+	}
1257
+      while (tolower (c) != (int) b);
1258
+
1259
+      c = tolower (*++needle);
1260
+      if (c == '\0')
1261
+	goto foundneedle;
1262
+      ++needle;
1263
+      goto jin;
1264
+
1265
+      for (;;)
1266
+        {
1267
+          register chartype a;
1268
+	  register const unsigned char *rhaystack, *rneedle;
1269
+
1270
+	  do
1271
+	    {
1272
+	      a = *++haystack;
1273
+	      if (a == '\0')
1274
+		goto ret0;
1275
+	      if (tolower (a) == (int) b)
1276
+		break;
1277
+	      a = *++haystack;
1278
+	      if (a == '\0')
1279
+		goto ret0;
1280
+shloop:
1281
+	      ;
1282
+	    }
1283
+          while (tolower (a) != (int) b);
1284
+
1285
+jin:	  a = *++haystack;
1286
+	  if (a == '\0')
1287
+	    goto ret0;
1288
+
1289
+	  if (tolower (a) != (int) c)
1290
+	    goto shloop;
1291
+
1292
+	  rhaystack = haystack-- + 1;
1293
+	  rneedle = needle;
1294
+	  a = tolower (*rneedle);
1295
+
1296
+	  if (tolower (*rhaystack) == (int) a)
1297
+	    do
1298
+	      {
1299
+		if (a == '\0')
1300
+		  goto foundneedle;
1301
+		++rhaystack;
1302
+		a = tolower (*++needle);
1303
+		if (tolower (*rhaystack) != (int) a)
1304
+		  break;
1305
+		if (a == '\0')
1306
+		  goto foundneedle;
1307
+		++rhaystack;
1308
+		a = tolower (*++needle);
1309
+	      }
1310
+	    while (tolower (*rhaystack) == (int) a);
1311
+
1312
+	  needle = rneedle;		/* took the register-poor approach */
1313
+
1314
+	  if (a == '\0')
1315
+	    break;
1316
+        }
1317
+    }
1318
+foundneedle:
1319
+  return (char*) haystack;
1320
+ret0:
1321
+  return 0;
1322
+}
1323
+#endif
1324
Index: lib/strnstr.c
1325
===================================================================
1326
RCS file: lib/strnstr.c
1327
diff -N lib/strnstr.c
1328
--- /dev/null	1 Jan 1970 00:00:00 -0000
1329
+++ lib/strnstr.c	17 May 2006 17:58:00 -0000	1.1.14.1
1330
@@ -0,0 +1,52 @@
1331
+/*
1332
+ *  Copyright (C) 2003 Nikos Mavroyanopoulos
1333
+ *
1334
+ *  This file is part of GNUTLS.
1335
+ *
1336
+ *  The GNUTLS library is free software; you can redistribute it and/or
1337
+ *  modify it under the terms of the GNU Lesser General Public   
1338
+ *  License as published by the Free Software Foundation; either 
1339
+ *  version 2.1 of the License, or (at your option) any later version.
1340
+ *
1341
+ *  This library is distributed in the hope that it will be useful,
1342
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
1343
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1344
+ *  Lesser General Public License for more details.
1345
+ *
1346
+ *  You should have received a copy of the GNU Lesser General Public
1347
+ *  License along with this library; if not, write to the Free Software
1348
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
1349
+ *
1350
+ */
1351
+
1352
+ /*
1353
+  * DW 2003/10/17:
1354
+  * Changed 'ssize_t' types to 'size_t'
1355
+  */
1356
+
1357
+#include "config.h"
1358
+#ifndef HAVE_STRNSTR
1359
+#include <string.h>
1360
+#include <util.h>
1361
+
1362
+char *strnstr(const char *haystack, const char *needle, size_t haystacklen)
1363
+{
1364
+        char *p;
1365
+        size_t plen;
1366
+        size_t len = strlen(needle);
1367
+
1368
+        if (*needle == '\0')    /* everything matches empty string */
1369
+                return (char*) haystack;
1370
+
1371
+        plen = haystacklen;
1372
+        for (p = (char*) haystack; p != NULL; p = memchr(p + 1, *needle, plen-1)) {
1373
+                plen = haystacklen - (p - haystack);
1374
+
1375
+                if (plen < len) return NULL;
1376
+
1377
+                if (strncmp(p, needle, len) == 0)
1378
+                        return (p);
1379
+        }
1380
+        return NULL;
1381
+}
1382
+#endif
1383
Index: src/MemBuf.c
1384
===================================================================
1385
RCS file: /cvsroot/squid/squid/src/MemBuf.c,v
1386
retrieving revision 1.11
1387
retrieving revision 1.9.10.4
1388
diff -p -u -b -r1.11 -r1.9.10.4
1389
--- src/MemBuf.c	16 Aug 2006 00:53:02 -0000	1.11
1390
+++ src/MemBuf.c	21 Aug 2006 19:48:09 -0000	1.9.10.4
1391
@@ -341,3 +341,15 @@ memBufReport(MemBuf * mb)
1392
     assert(mb);
1393
     memBufPrintf(mb, "memBufReport is not yet implemented @?@\n");
1394
 }
1395
+
1396
+int
1397
+memBufRead(int fd, MemBuf * mb)
1398
+{
1399
+    int len;
1400
+    if (mb->capacity == mb->size)
1401
+	memBufGrow(mb, SQUID_TCP_SO_RCVBUF);
1402
+    len = FD_READ_METHOD(fd, mb->buf + mb->size, mb->capacity - mb->size);
1403
+    if (len > 0)
1404
+	mb->size += len;
1405
+    return len;
1406
+}
1407
Index: src/cache_cf.c
1408
===================================================================
1409
RCS file: /cvsroot/squid/squid/src/cache_cf.c,v
1410
retrieving revision 1.86
1411
retrieving revision 1.61.4.12
1412
diff -p -u -b -r1.86 -r1.61.4.12
1413
--- src/cache_cf.c	10 Dec 2006 05:51:43 -0000	1.86
1414
+++ src/cache_cf.c	12 Dec 2006 22:49:42 -0000	1.61.4.12
1415
@@ -2389,6 +2389,587 @@ check_null_body_size_t(dlink_list bodyli
1416
     return bodylist.head == NULL;
1417
 }
1418
 
1419
+#ifdef HS_FEAT_ICAP
1420
+
1421
+/***************************************************
1422
+ * prototypes
1423
+ */
1424
+static int icap_service_process(icap_service * s);
1425
+static void icap_service_init(icap_service * s);
1426
+static void icap_service_destroy(icap_service * s);
1427
+icap_service *icap_service_lookup(char *name);
1428
+static int icap_class_process(icap_class * c);
1429
+static void icap_class_destroy(icap_class * c);
1430
+static void icap_access_destroy(icap_access * a);
1431
+static void dump_wordlist(StoreEntry * entry, const char *name, const wordlist * list);
1432
+static void icap_class_add(icap_class * c);
1433
+
1434
+/***************************************************
1435
+ * icap_service
1436
+ */
1437
+
1438
+/* 
1439
+ * example:
1440
+ * icap_service reqmode_precache 0 icap://192.168.0.1:1344/respmod
1441
+ */
1442
+
1443
+static void
1444
+parse_icap_service_type(IcapConfig * cfg)
1445
+{
1446
+    char *token;
1447
+    icap_service *A = NULL;
1448
+    icap_service *B = NULL;
1449
+    icap_service **T = NULL;
1450
+
1451
+    A = cbdataAlloc(icap_service);
1452
+    icap_service_init(A);
1453
+    parse_string(&A->name);
1454
+    parse_string(&A->type_name);
1455
+    parse_ushort(&A->bypass);
1456
+    parse_string(&A->uri);
1457
+    while ((token = strtok(NULL, w_space))) {
1458
+	if (strcasecmp(token, "no-keep-alive") == 0) {
1459
+	    A->keep_alive = 0;
1460
+	} else {
1461
+	    debug(3, 0) ("parse_peer: token='%s'\n", token);
1462
+	    self_destruct();
1463
+	}
1464
+    }
1465
+    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);
1466
+    if (icap_service_process(A)) {
1467
+	/* put into linked list */
1468
+	for (B = cfg->service_head, T = &cfg->service_head; B; T = &B->next, B = B->next);
1469
+	*T = A;
1470
+    } else {
1471
+	/* clean up structure */
1472
+	debug(3, 0) ("parse_icap_service_type (line %d): skipping %s\n", config_lineno, A->name);
1473
+	icap_service_destroy(A);
1474
+	cbdataFree(A);
1475
+    }
1476
+
1477
+}
1478
+
1479
+static void
1480
+dump_icap_service_type(StoreEntry * e, const char *name, IcapConfig cfg)
1481
+{
1482
+    icap_service *current_node = NULL;
1483
+
1484
+    if (!cfg.service_head) {
1485
+	storeAppendPrintf(e, "%s 0\n", name);
1486
+	return;
1487
+    }
1488
+    current_node = cfg.service_head;
1489
+
1490
+    while (current_node) {
1491
+	storeAppendPrintf(e, "%s %s %s %d %s", name, current_node->name, current_node->type_name, current_node->bypass, current_node->uri);
1492
+	if (current_node->keep_alive == 0) {
1493
+	    storeAppendPrintf(e, " no-keep-alive");
1494
+	}
1495
+	storeAppendPrintf(e, "\n");
1496
+	current_node = current_node->next;
1497
+    }
1498
+
1499
+}
1500
+
1501
+static void
1502
+free_icap_service_type(IcapConfig * cfg)
1503
+{
1504
+    while (cfg->service_head) {
1505
+	icap_service *current_node = cfg->service_head;
1506
+	cfg->service_head = current_node->next;
1507
+	icap_service_destroy(current_node);
1508
+	cbdataFree(current_node);
1509
+    }
1510
+}
1511
+
1512
+/* 
1513
+ * parse the raw string and cache some parts that are needed later 
1514
+ * returns 1 if everything was ok
1515
+ */
1516
+static int
1517
+icap_service_process(icap_service * s)
1518
+{
1519
+    char *start, *end, *tempEnd;
1520
+    char *tailp;
1521
+    unsigned int len;
1522
+    int port_in_uri, resource_in_uri = 0;
1523
+    s->type = icapServiceToType(s->type_name);
1524
+    if (s->type >= ICAP_SERVICE_MAX) {
1525
+	debug(3, 0) ("icap_service_process (line %d): wrong service type %s\n", config_lineno, s->type_name);
1526
+	return 0;
1527
+    }
1528
+    if (s->type == ICAP_SERVICE_REQMOD_PRECACHE)
1529
+	s->method = ICAP_METHOD_REQMOD;
1530
+    else if (s->type == ICAP_SERVICE_REQMOD_PRECACHE)
1531
+	s->method = ICAP_METHOD_REQMOD;
1532
+    else if (s->type == ICAP_SERVICE_REQMOD_POSTCACHE)
1533
+	s->method = ICAP_METHOD_REQMOD;
1534
+    else if (s->type == ICAP_SERVICE_RESPMOD_PRECACHE)
1535
+	s->method = ICAP_METHOD_RESPMOD;
1536
+    else if (s->type == ICAP_SERVICE_RESPMOD_POSTCACHE)
1537
+	s->method = ICAP_METHOD_RESPMOD;
1538
+    debug(3, 5) ("icap_service_process (line %d): type=%s\n", config_lineno, icapServiceToStr(s->type));
1539
+    if (strncmp(s->uri, "icap://", 7) != 0) {
1540
+	debug(3, 0) ("icap_service_process (line %d): wrong uri: %s\n", config_lineno, s->uri);
1541
+	return 0;
1542
+    }
1543
+    start = s->uri + 7;
1544
+    if ((end = strchr(start, ':')) != NULL) {
1545
+	/* ok */
1546
+	port_in_uri = 1;
1547
+	debug(3, 5) ("icap_service_process (line %d): port given\n", config_lineno);
1548
+    } else {
1549
+	/* ok */
1550
+	port_in_uri = 0;
1551
+	debug(3, 5) ("icap_service_process (line %d): no port given\n", config_lineno);
1552
+    }
1553
+
1554
+    if ((tempEnd = strchr(start, '/')) != NULL) {
1555
+	/* ok */
1556
+	resource_in_uri = 1;
1557
+	debug(3, 5) ("icap_service_process (line %d): resource given\n", config_lineno);
1558
+	if (end == '\0') {
1559
+	    end = tempEnd;
1560
+	}
1561
+    } else {
1562
+	/* ok */
1563
+	resource_in_uri = 0;
1564
+	debug(3, 5) ("icap_service_process (line %d): no resource given\n", config_lineno);
1565
+    }
1566
+
1567
+    tempEnd = strchr(start, '\0');
1568
+    if (end == '\0') {
1569
+	end = tempEnd;
1570
+    }
1571
+    len = end - start;
1572
+    s->hostname = xstrndup(start, len + 1);
1573
+    s->hostname[len] = 0;
1574
+    debug(3, 5) ("icap_service_process (line %d): hostname=%s\n", config_lineno, s->hostname);
1575
+    start = end;
1576
+
1577
+    if (port_in_uri) {
1578
+	start++;		/* skip ':' */
1579
+	if (resource_in_uri)
1580
+	    end = strchr(start, '/');
1581
+	else
1582
+	    end = strchr(start, '\0');
1583
+	s->port = strtoul(start, &tailp, 0) % 65536;
1584
+	if (tailp != end) {
1585
+	    debug(3, 0) ("icap_service_process (line %d): wrong service uri (port could not be parsed): %s\n", config_lineno, s->uri);
1586
+	    return 0;
1587
+	}
1588
+	debug(3, 5) ("icap_service_process (line %d): port=%d\n", config_lineno, s->port);
1589
+	start = end;
1590
+    } else {
1591
+	/* no explicit ICAP port; first ask by getservbyname or default to
1592
+	 * hardwired port 1344 per ICAP specification section 4.2 */
1593
+	struct servent *serv = getservbyname("icap", "tcp");
1594
+	if (serv) {
1595
+	    s->port = htons(serv->s_port);
1596
+	    debug(3, 5) ("icap_service_process (line %d): default port=%d getservbyname(icap,tcp)\n", config_lineno, s->port);
1597
+	} else {
1598
+	    s->port = 1344;
1599
+	    debug(3, 5) ("icap_service_process (line %d): default hardwired port=%d\n", config_lineno, s->port);
1600
+	}
1601
+    }
1602
+
1603
+    if (resource_in_uri) {
1604
+	start++;		/* skip '/' */
1605
+	/* the rest is resource name */
1606
+	end = strchr(start, '\0');
1607
+	len = end - start;
1608
+	if (len > 1024) {
1609
+	    debug(3, 0) ("icap_service_process (line %d): long resource name (>1024), probably wrong\n", config_lineno);
1610
+	}
1611
+	s->resource = xstrndup(start, len + 1);
1612
+	s->resource[len] = 0;
1613
+	debug(3, 5) ("icap_service_process (line %d): service=%s\n", config_lineno, s->resource);
1614
+    }
1615
+    /* check bypass */
1616
+    if ((s->bypass != 0) && (s->bypass != 1)) {
1617
+	debug(3, 0) ("icap_service_process (line %d): invalid bypass value\n", config_lineno);
1618
+	return 0;
1619
+    }
1620
+    return 1;
1621
+}
1622
+
1623
+/*
1624
+ * constructor
1625
+ */
1626
+static void
1627
+icap_service_init(icap_service * s)
1628
+{
1629
+    s->type = ICAP_SERVICE_MAX;	/* means undefined */
1630
+    s->preview = Config.icapcfg.preview_size;
1631
+    s->opt = 0;
1632
+    s->keep_alive = 1;
1633
+    s->istag = StringNull;
1634
+    s->transfer_preview = StringNull;
1635
+    s->transfer_ignore = StringNull;
1636
+    s->transfer_complete = StringNull;
1637
+}
1638
+
1639
+/*
1640
+ * destructor
1641
+ * frees only strings, but don't touch the linked list
1642
+ */
1643
+static void
1644
+icap_service_destroy(icap_service * s)
1645
+{
1646
+    xfree(s->name);
1647
+    xfree(s->uri);
1648
+    xfree(s->type_name);
1649
+    xfree(s->hostname);
1650
+    xfree(s->resource);
1651
+    assert(s->opt == 0);	/* there should be no opt request running now */
1652
+    stringClean(&s->istag);
1653
+    stringClean(&s->transfer_preview);
1654
+    stringClean(&s->transfer_ignore);
1655
+    stringClean(&s->transfer_complete);
1656
+}
1657
+
1658
+icap_service *
1659
+icap_service_lookup(char *name)
1660
+{
1661
+    icap_service *iter;
1662
+    for (iter = Config.icapcfg.service_head; iter; iter = iter->next) {
1663
+	if (!strcmp(name, iter->name)) {
1664
+	    return iter;
1665
+	}
1666
+    }
1667
+    return NULL;
1668
+}
1669
+
1670
+/***************************************************
1671
+ * icap_service_list
1672
+ */
1673
+
1674
+static void
1675
+icap_service_list_add(icap_service_list ** isl, char *service_name)
1676
+{
1677
+    icap_service_list **iter;
1678
+    icap_service_list *new;
1679
+    icap_service *gbl_service;
1680
+    int i;
1681
+    int max_services;
1682
+
1683
+    new = memAllocate(MEM_ICAP_SERVICE_LIST);
1684
+    /* Found all services with that name, and add to the array */
1685
+    max_services = sizeof(new->services) / sizeof(icap_service *);
1686
+    gbl_service = Config.icapcfg.service_head;
1687
+    i = 0;
1688
+    while (gbl_service && i < max_services) {
1689
+	if (!strcmp(service_name, gbl_service->name))
1690
+	    new->services[i++] = gbl_service;
1691
+	gbl_service = gbl_service->next;
1692
+    }
1693
+    new->nservices = i;
1694
+
1695
+    if (*isl) {
1696
+	iter = isl;
1697
+	while ((*iter)->next)
1698
+	    iter = &((*iter)->next);
1699
+	(*iter)->next = new;
1700
+    } else {
1701
+	*isl = new;
1702
+    }
1703
+}
1704
+
1705
+/*
1706
+ * free the linked list without touching references icap_service
1707
+ */
1708
+static void
1709
+icap_service_list_destroy(icap_service_list * isl)
1710
+{
1711
+    icap_service_list *current;
1712
+    icap_service_list *next;
1713
+
1714
+    current = isl;
1715
+    while (current) {
1716
+	next = current->next;
1717
+	memFree(current, MEM_ICAP_SERVICE_LIST);
1718
+	current = next;
1719
+    }
1720
+}
1721
+
1722
+/***************************************************
1723
+ * icap_class
1724
+ */
1725
+static void
1726
+parse_icap_class_type(IcapConfig * cfg)
1727
+{
1728
+    icap_class *s = NULL;
1729
+
1730
+    s = memAllocate(MEM_ICAP_CLASS);
1731
+    parse_string(&s->name);
1732
+    parse_wordlist(&s->services);
1733
+
1734
+    if (icap_class_process(s)) {
1735
+	/* if ok, put into linked list */
1736
+	icap_class_add(s);
1737
+    } else {
1738
+	/* clean up structure */
1739
+	debug(3, 0) ("parse_icap_class_type (line %d): skipping %s\n", config_lineno, s->name);
1740
+	icap_class_destroy(s);
1741
+	memFree(s, MEM_ICAP_CLASS);
1742
+    }
1743
+}
1744
+
1745
+static void
1746
+dump_icap_class_type(StoreEntry * e, const char *name, IcapConfig cfg)
1747
+{
1748
+    icap_class *current_node = NULL;
1749
+    LOCAL_ARRAY(char, nom, 64);
1750
+
1751
+    if (!cfg.class_head) {
1752
+	storeAppendPrintf(e, "%s 0\n", name);
1753
+	return;
1754
+    }
1755
+    current_node = cfg.class_head;
1756
+
1757
+    while (current_node) {
1758
+	snprintf(nom, 64, "%s %s", name, current_node->name);
1759
+	dump_wordlist(e, nom, current_node->services);
1760
+	current_node = current_node->next;
1761
+    }
1762
+}
1763
+
1764
+static void
1765
+free_icap_class_type(IcapConfig * cfg)
1766
+{
1767
+    while (cfg->class_head) {
1768
+	icap_class *current_node = cfg->class_head;
1769
+	cfg->class_head = current_node->next;
1770
+	icap_class_destroy(current_node);
1771
+	memFree(current_node, MEM_ICAP_CLASS);
1772
+    }
1773
+}
1774
+
1775
+/*
1776
+ * process services list, return 1, if at least one service was found
1777
+ */
1778
+static int
1779
+icap_class_process(icap_class * c)
1780
+{
1781
+    icap_service_list *isl = NULL;
1782
+    wordlist *iter;
1783
+    icap_service *service;
1784
+    /* take services list and build icap_service_list from it */
1785
+    for (iter = c->services; iter; iter = iter->next) {
1786
+	service = icap_service_lookup(iter->key);
1787
+	if (service) {
1788
+	    icap_service_list_add(&isl, iter->key);
1789
+	} else {
1790
+	    debug(3, 0) ("icap_class_process (line %d): skipping service %s in class %s\n", config_lineno, iter->key, c->name);
1791
+	}
1792
+    }
1793
+
1794
+    if (isl) {
1795
+	c->isl = isl;
1796
+	return 1;
1797
+    }
1798
+    return 0;
1799
+}
1800
+
1801
+/*
1802
+ * search for an icap_class in the global IcapConfig
1803
+ * classes with hidden-flag are skipped
1804
+ */
1805
+static icap_class *
1806
+icap_class_lookup(char *name)
1807
+{
1808
+    icap_class *iter;
1809
+    for (iter = Config.icapcfg.class_head; iter; iter = iter->next) {
1810
+	if ((!strcmp(name, iter->name)) && (!iter->hidden)) {
1811
+	    return iter;
1812
+	}
1813
+    }
1814
+    return NULL;
1815
+}
1816
+
1817
+/*
1818
+ * adds an icap_class to the global IcapConfig
1819
+ */
1820
+static void
1821
+icap_class_add(icap_class * c)
1822
+{
1823
+    icap_class *cp = NULL;
1824
+    icap_class **t = NULL;
1825
+    IcapConfig *cfg = &Config.icapcfg;
1826
+    if (c) {
1827
+	for (cp = cfg->class_head, t = &cfg->class_head; cp; t = &cp->next, cp = cp->next);
1828
+	*t = c;
1829
+    }
1830
+}
1831
+
1832
+/*
1833
+ * free allocated memory inside icap_class
1834
+ */
1835
+static void
1836
+icap_class_destroy(icap_class * c)
1837
+{
1838
+    xfree(c->name);
1839
+    wordlistDestroy(&c->services);
1840
+    icap_service_list_destroy(c->isl);
1841
+}
1842
+
1843
+/***************************************************
1844
+ * icap_access
1845
+ */
1846
+
1847
+/* format: icap_access <servicename> {allow|deny} acl, ... */
1848
+static void
1849
+parse_icap_access_type(IcapConfig * cfg)
1850
+{
1851
+    icap_access *A = NULL;
1852
+    icap_access *B = NULL;
1853
+    icap_access **T = NULL;
1854
+    icap_service *s = NULL;
1855
+    icap_class *c = NULL;
1856
+    ushort no_class = 0;
1857
+
1858
+    A = memAllocate(MEM_ICAP_ACCESS);
1859
+    parse_string(&A->service_name);
1860
+
1861
+    /* 
1862
+     * try to find a class with the given name first. if not found, search 
1863
+     * the services. if a service is found, create a new hidden class with 
1864
+     * only this service. this is for backward compatibility.
1865
+     *
1866
+     * the special classname All is allowed only in deny rules, because
1867
+     * the class is not used there.
1868
+     */
1869
+    if (!strcmp(A->service_name, "None")) {
1870
+	no_class = 1;
1871
+    } else {
1872
+	A->class = icap_class_lookup(A->service_name);
1873
+	if (!A->class) {
1874
+	    s = icap_service_lookup(A->service_name);
1875
+	    if (s) {
1876
+		c = memAllocate(MEM_ICAP_CLASS);
1877
+		c->name = xstrdup("(hidden)");
1878
+		c->hidden = 1;
1879
+		wordlistAdd(&c->services, A->service_name);
1880
+		c->isl = memAllocate(MEM_ICAP_SERVICE_LIST);
1881
+		/* FIXME:luc: check what access do */
1882
+		c->isl->services[0] = s;
1883
+		c->isl->nservices = 1;
1884
+		icap_class_add(c);
1885
+		A->class = c;
1886
+	    } else {
1887
+		debug(3, 0) ("parse_icap_access_type (line %d): servicename %s not found. skipping.\n", config_lineno, A->service_name);
1888
+		memFree(A, MEM_ICAP_ACCESS);
1889
+		return;
1890
+	    }
1891
+	}
1892
+    }
1893
+
1894
+    aclParseAccessLine(&(A->access));
1895
+    debug(3, 5) ("parse_icap_access_type (line %d): %s\n", config_lineno, A->service_name);
1896
+
1897
+    /* check that All class is only used in deny rule */
1898
+    if (no_class && A->access->allow) {
1899
+	memFree(A, MEM_ICAP_ACCESS);
1900
+	debug(3, 0) ("parse_icap_access (line %d): special class 'None' only allowed in deny rule. skipping.\n", config_lineno);
1901
+	return;
1902
+    }
1903
+    if (A->access) {
1904
+	for (B = cfg->access_head, T = &cfg->access_head; B; T = &B->next, B = B->next);
1905
+	*T = A;
1906
+    } else {
1907
+	debug(3, 0) ("parse_icap_access_type (line %d): invalid line skipped\n", config_lineno);
1908
+	memFree(A, MEM_ICAP_ACCESS);
1909
+    }
1910
+}
1911
+
1912
+static void
1913
+dump_icap_access_type(StoreEntry * e, const char *name, IcapConfig cfg)
1914
+{
1915
+    icap_access *current_node = NULL;
1916
+    LOCAL_ARRAY(char, nom, 64);
1917
+
1918
+    if (!cfg.access_head) {
1919
+	storeAppendPrintf(e, "%s 0\n", name);
1920
+	return;
1921
+    }
1922
+    current_node = cfg.access_head;
1923
+
1924
+    while (current_node) {
1925
+	snprintf(nom, 64, "%s %s", name, current_node->service_name);
1926
+	dump_acl_access(e, nom, current_node->access);
1927
+	current_node = current_node->next;
1928
+    }
1929
+}
1930
+
1931
+static void
1932
+free_icap_access_type(IcapConfig * cfg)
1933
+{
1934
+    while (cfg->access_head) {
1935
+	icap_access *current_node = cfg->access_head;
1936
+	cfg->access_head = current_node->next;
1937
+	icap_access_destroy(current_node);
1938
+	memFree(current_node, MEM_ICAP_ACCESS);
1939
+    }
1940
+}
1941
+
1942
+/*
1943
+ * destructor
1944
+ * frees everything but the linked list
1945
+ */
1946
+static void
1947
+icap_access_destroy(icap_access * a)
1948
+{
1949
+    xfree(a->service_name);
1950
+    aclDestroyAccessList(&a->access);
1951
+}
1952
+
1953
+/***************************************************
1954
+ * for debugging purposes only
1955
+ */
1956
+void
1957
+dump_icap_config(IcapConfig * cfg)
1958
+{
1959
+    icap_service *s_iter;
1960
+    icap_class *c_iter;
1961
+    icap_access *a_iter;
1962
+    icap_service_list *isl_iter;
1963
+    acl_list *l;
1964
+    debug(3, 0) ("IcapConfig: onoff        = %d\n", cfg->onoff);
1965
+    debug(3, 0) ("IcapConfig: service_head = %d\n", (int) cfg->service_head);
1966
+    debug(3, 0) ("IcapConfig: class_head   = %d\n", (int) cfg->class_head);
1967
+    debug(3, 0) ("IcapConfig: access_head  = %d\n", (int) cfg->access_head);
1968
+
1969
+    debug(3, 0) ("IcapConfig: services =\n");
1970
+    for (s_iter = cfg->service_head; s_iter; s_iter = s_iter->next) {
1971
+	printf("  %s: \n", s_iter->name);
1972
+	printf("    bypass   = %d\n", s_iter->bypass);
1973
+	printf("    hostname = %s\n", s_iter->hostname);
1974
+	printf("    port     = %d\n", s_iter->port);
1975
+	printf("    resource = %s\n", s_iter->resource);
1976
+    }
1977
+    debug(3, 0) ("IcapConfig: classes =\n");
1978
+    for (c_iter = cfg->class_head; c_iter; c_iter = c_iter->next) {
1979
+	printf("  %s: \n", c_iter->name);
1980
+	printf("    services = \n");
1981
+	for (isl_iter = c_iter->isl; isl_iter; isl_iter = isl_iter->next) {
1982
+	    int i;
1983
+	    for (i = 0; i < isl_iter->nservices; i++)
1984
+		printf("      %s\n", isl_iter->services[i]->name);
1985
+	}
1986
+    }
1987
+    debug(3, 0) ("IcapConfig: access =\n");
1988
+    for (a_iter = cfg->access_head; a_iter; a_iter = a_iter->next) {
1989
+	printf("  service_name  = %s\n", a_iter->service_name);
1990
+	printf("    access        = %s", a_iter->access->allow ? "allow" : "deny");
1991
+	for (l = a_iter->access->acl_list; l != NULL; l = l->next) {
1992
+	    printf(" %s%s",
1993
+		l->op ? null_string : "!",
1994
+		l->acl->name);
1995
+	}
1996
+	printf("\n");
1997
+    }
1998
+}
1999
+#endif /* HS_FEAT_ICAP */
2000
 
2001
 static void
2002
 parse_kb_size_t(squid_off_t * var)
2003
Index: src/cbdata.c
2004
===================================================================
2005
RCS file: /cvsroot/squid/squid/src/cbdata.c,v
2006
retrieving revision 1.18
2007
retrieving revision 1.18.8.1
2008
diff -p -u -b -r1.18 -r1.18.8.1
2009
--- src/cbdata.c	12 May 2006 22:51:56 -0000	1.18
2010
+++ src/cbdata.c	17 May 2006 17:58:00 -0000	1.18.8.1
2011
@@ -179,6 +179,10 @@ cbdataInit(void)
2012
     CREATE_CBDATA(statefulhelper);
2013
     CREATE_CBDATA(helper_stateful_server);
2014
     CREATE_CBDATA(HttpStateData);
2015
+#ifdef HS_FEAT_ICAP
2016
+    CREATE_CBDATA(IcapStateData);
2017
+    CREATE_CBDATA(icap_service);
2018
+#endif
2019
     CREATE_CBDATA_FREE(peer, peerDestroy);
2020
     CREATE_CBDATA(ps_state);
2021
     CREATE_CBDATA(RemovalPolicy);
2022
Index: src/cf.data.pre
2023
===================================================================
2024
RCS file: /cvsroot/squid/squid/src/cf.data.pre,v
2025
retrieving revision 1.161
2026
retrieving revision 1.100.4.12
2027
diff -p -u -b -r1.161 -r1.100.4.12
2028
--- src/cf.data.pre	29 Nov 2006 00:52:57 -0000	1.161
2029
+++ src/cf.data.pre	12 Dec 2006 22:49:42 -0000	1.100.4.12
2030
@@ -3189,7 +3189,6 @@ DOC_START
2031
 	ensure correct results it is best to set server_persistent_connections
2032
 	to off when using this directive in such configurations.
2033
 DOC_END
2034
-
2035
 NAME: reply_header_max_size
2036
 COMMENT: (KB)
2037
 TYPE: b_size_t
2038
@@ -3458,6 +3457,187 @@ DOC_START
2039
 DOC_END
2040
 
2041
 COMMENT_START
2042
+ ICAP OPTIONS
2043
+ -----------------------------------------------------------------------------
2044
+COMMENT_END
2045
+
2046
+NAME: icap_enable
2047
+TYPE: onoff
2048
+IFDEF: HS_FEAT_ICAP
2049
+COMMENT: on|off
2050
+LOC: Config.icapcfg.onoff
2051
+DEFAULT: off
2052
+DOC_START
2053
+	If you want to enable the ICAP client module, set this to on.
2054
+DOC_END
2055
+
2056
+NAME: icap_preview_enable
2057
+TYPE: onoff
2058
+IFDEF: HS_FEAT_ICAP
2059
+COMMENT: on|off
2060
+LOC: Config.icapcfg.preview_enable
2061
+DEFAULT: off
2062
+DOC_START
2063
+	Set this to 'on' if you want to enable the ICAP preview
2064
+	feature in Squid.
2065
+DOC_END
2066
+
2067
+NAME: icap_preview_size
2068
+TYPE: int
2069
+IFDEF: HS_FEAT_ICAP
2070
+LOC: Config.icapcfg.preview_size
2071
+DEFAULT: -1
2072
+DOC_START
2073
+	The default size of preview data to be sent to the ICAP server.
2074
+	-1 means no preview. This value might be overwritten on a per server
2075
+	basis by OPTIONS requests.
2076
+DOC_END
2077
+
2078
+NAME: icap_check_interval
2079
+TYPE: int
2080
+IFDEF: HS_FEAT_ICAP
2081
+LOC: Config.icapcfg.check_interval
2082
+DEFAULT: 300
2083
+DOC_START
2084
+        If an ICAP server does not respond, it gets marked as unreachable. Squid
2085
+	will try again to reach it after this time.
2086
+DOC_END
2087
+
2088
+NAME: icap_send_client_ip
2089
+TYPE: onoff
2090
+IFDEF: HS_FEAT_ICAP
2091
+COMMENT: on|off
2092
+LOC: Config.icapcfg.send_client_ip
2093
+DEFAULT: off
2094
+DOC_START
2095
+	Allows Squid to add the "X-Client-IP" header if requested by
2096
+	an ICAP service in it's response to OPTIONS.
2097
+DOC_END
2098
+
2099
+NAME: icap_send_server_ip
2100
+TYPE: onoff
2101
+IFDEF: HS_FEAT_ICAP
2102
+COMMENT: on|off
2103
+LOC: Config.icapcfg.send_server_ip
2104
+DEFAULT: off
2105
+DOC_START
2106
+	Allows Squid to add the "X-Server-IP" header if requested by
2107
+	an ICAP service in it's response to OPTIONS.
2108
+DOC_END
2109
+
2110
+NAME: icap_send_auth_user
2111
+TYPE: onoff
2112
+IFDEF: HS_FEAT_ICAP
2113
+COMMENT: on|off
2114
+LOC: Config.icapcfg.send_auth_user
2115
+DEFAULT: off
2116
+DOC_START
2117
+	Allows Squid to add the "X-Authenticated-User" header if requested
2118
+	by an ICAP service in it's response to OPTIONS.
2119
+DOC_END
2120
+
2121
+NAME: icap_auth_scheme
2122
+TYPE: string
2123
+IFDEF: HS_FEAT_ICAP
2124
+LOC: Config.icapcfg.auth_scheme
2125
+DEFAULT: Local://%u
2126
+DOC_START
2127
+	Authentification scheme to pass to ICAP requests if
2128
+	icap_send_auth_user is enabled. The first occurence of "%u"
2129
+	is replaced by the authentified user name. If no "%u" is found,
2130
+	the username is added at the end of the scheme.
2131
+	
2132
+	See http://www.ietf.org/internet-drafts/draft-stecher-icap-subid-00.txt,
2133
+	section 3.4 for details on this.
2134
+
2135
+	Examples:
2136
+
2137
+	icap_auth_scheme Local://%u
2138
+	icap_auth_scheme LDAP://ldap-server/cn=%u,dc=company,dc=com
2139
+	icap_auth_scheme WinNT://nt-domain/%u
2140
+	icap_auth_scheme Radius://radius-server/%u
2141
+DOC_END
2142
+
2143
+NAME: icap_service
2144
+TYPE: icap_service_type
2145
+IFDEF: HS_FEAT_ICAP
2146
+LOC: Config.icapcfg
2147
+DEFAULT: none
2148
+DOC_START
2149
+	Defines a single ICAP service
2150
+
2151
+	icap_service servicename vectoring_point bypass service_url [options ...]
2152
+
2153
+	vectoring_point = reqmod_precache|reqmod_postcache|respmod_precache|respmod_postcache
2154
+		This specifies at which point of request processing the ICAP
2155
+		service should be plugged in.
2156
+	bypass = 1|0   
2157
+		If set to 1 and the ICAP server cannot be reached, the request will go 
2158
+		through without being processed by an ICAP server
2159
+	service_url = icap://servername:port/service
2160
+
2161
+	Options: 
2162
+
2163
+        no-keep-alive	To always close the connection to icap server
2164
+        		after the transaction completes
2165
+
2166
+
2167
+	Note: reqmod_precache and respmod_postcache is not yet implemented
2168
+
2169
+	Load-balancing and high availability:
2170
+	You can obtain load-balancing and high availability by defining a
2171
+	named service with different definitions.  Then, the client
2172
+	loops through the different entities of the service providing
2173
+	load-balancing. If an entity is marked as unreachable, the client goes
2174
+	one step further to the next entity: you have the high-availability.
2175
+	See the service_1 definition below
2176
+
2177
+Example:
2178
+icap_service service_1 reqmod_precache 0 icap://icap1.mydomain.net:1344/reqmod
2179
+icap_service service_1 reqmod_precache 0 icap://icap2.mydomain.net:1344/reqmod no-keep-alive
2180
+icap_service service_2 respmod_precache 0 icap://icap3.mydomain.net:1344/respmod 
2181
+DOC_END
2182
+
2183
+NAME: icap_class
2184
+TYPE: icap_class_type
2185
+IFDEF: HS_FEAT_ICAP
2186
+LOC: Config.icapcfg
2187
+DEFAULT: none
2188
+DOC_START
2189
+	Defines an ICAP service chain. If there are multiple services per 
2190
+	vectoring point, they are processed in the specified order.
2191
+
2192
+	icap_class classname servicename...
2193
+
2194
+Example:
2195
+icap_class class_1 service_1 service_2
2196
+icap class class_2 service_1 service_3
2197
+DOC_END
2198
+
2199
+NAME: icap_access
2200
+TYPE: icap_access_type
2201
+IFDEF: HS_FEAT_ICAP
2202
+LOC: Config.icapcfg
2203
+DEFAULT: none
2204
+DOC_START
2205
+	Redirects a request through an ICAP service class, depending
2206
+	on given acls
2207
+
2208
+	icap_access classname allow|deny [!]aclname...
2209
+
2210
+	The icap_access statements are processed in the order they appear in
2211
+	this configuration file. If an access list matches, the processing stops. 
2212
+	For an "allow" rule, the specified class is used for the request. A "deny" 
2213
+	rule simply stops processing without using the class. You can also use the 
2214
+	special classname "None". 
2215
+	
2216
+	For backward compatibility, it is also possible to use services 
2217
+	directly here.
2218
+Example:
2219
+icap_access class_1 allow all
2220
+DOC_END
2221
+
2222
+COMMENT_START
2223
  MISCELLANEOUS
2224
  -----------------------------------------------------------------------------
2225
 COMMENT_END
2226
Index: src/cf_gen_defines
2227
===================================================================
2228
RCS file: /cvsroot/squid/squid/src/cf_gen_defines,v
2229
retrieving revision 1.7
2230
retrieving revision 1.6.8.2
2231
diff -p -u -b -r1.7 -r1.6.8.2
2232
--- src/cf_gen_defines	31 May 2006 19:51:14 -0000	1.7
2233
+++ src/cf_gen_defines	4 Jun 2006 14:15:43 -0000	1.6.8.2
2234
@@ -22,6 +22,7 @@ BEGIN {
2235
 	define["USE_WCCP"]="--enable-wccp"
2236
 	define["USE_WCCPv2"]="--enable-wccpv2"
2237
 	define["WIP_FWD_LOG"]="--enable-forward-log"
2238
+	define["HS_FEAT_ICAP"]="--enable-icap-support"
2239
 }
2240
 /^IFDEF:/ {
2241
 	if (define[$2] != "")
2242
Index: src/client_side.c
2243
===================================================================
2244
--- src/client_side.c.orig	Wed Mar 14 15:11:26 2007
2245
+++ src/client_side.c	Sun Mar 18 11:16:30 2007
2246
@@ -109,7 +109,7 @@ static const char *const crlf = "\r\n";
2247
 static CWCB clientWriteComplete;
2248
 static CWCB clientWriteBodyComplete;
2249
 static PF clientReadRequest;
2250
-static PF connStateFree;
2251
+PF connStateFree;
2252
 static PF requestTimeout;
2253
 static PF clientLifetimeTimeout;
2254
 static int clientCheckTransferDone(clientHttpRequest *);
2255
@@ -141,12 +141,12 @@ static void clientSetKeepaliveFlag(clien
2256
 static void clientPackRangeHdr(const HttpReply * rep, const HttpHdrRangeSpec * spec, String boundary, MemBuf * mb);
2257
 static void clientPackTermBound(String boundary, MemBuf * mb);
2258
 static void clientInterpretRequestHeaders(clientHttpRequest *);
2259
-static void clientProcessRequest(clientHttpRequest *);
2260
+void clientProcessRequest(clientHttpRequest *);
2261
 static void clientProcessExpired(void *data);
2262
 static void clientProcessOnlyIfCachedMiss(clientHttpRequest * http);
2263
-static int clientCachable(clientHttpRequest * http);
2264
-static int clientHierarchical(clientHttpRequest * http);
2265
-static int clientCheckContentLength(request_t * r);
2266
+int clientCachable(clientHttpRequest * http);
2267
+int clientHierarchical(clientHttpRequest * http);
2268
+int clientCheckContentLength(request_t * r);
2269
 static DEFER httpAcceptDefer;
2270
 static log_type clientProcessRequest2(clientHttpRequest * http);
2271
 static int clientReplyBodyTooLarge(clientHttpRequest *, squid_off_t clen);
2272
@@ -157,15 +157,18 @@ static void clientAccessCheck(void *data
2273
 static void clientAccessCheckDone(int answer, void *data);
2274
 static void clientAccessCheck2(void *data);
2275
 static void clientAccessCheckDone2(int answer, void *data);
2276
-static BODY_HANDLER clientReadBody;
2277
+BODY_HANDLER clientReadBody;
2278
 static void clientAbortBody(request_t * req);
2279
 #if USE_SSL
2280
 static void httpsAcceptSSL(ConnStateData * connState, SSL_CTX * sslContext);
2281
 #endif
2282
 static int varyEvaluateMatch(StoreEntry * entry, request_t * request);
2283
 static int modifiedSince(StoreEntry *, request_t *);
2284
-static StoreEntry *clientCreateStoreEntry(clientHttpRequest *, method_t, request_flags);
2285
+StoreEntry *clientCreateStoreEntry(clientHttpRequest *, method_t, request_flags);
2286
 static inline int clientNatLookup(ConnStateData * conn);
2287
+#if HS_FEAT_ICAP
2288
+static int clientIcapReqMod(clientHttpRequest * http);
2289
+#endif
2290
 
2291
 #if USE_IDENT
2292
 static void
2293
@@ -383,7 +386,7 @@ clientOnlyIfCached(clientHttpRequest * h
2294
 	EBIT_TEST(r->cache_control->mask, CC_ONLY_IF_CACHED);
2295
 }
2296
 
2297
-static StoreEntry *
2298
+StoreEntry *
2299
 clientCreateStoreEntry(clientHttpRequest * h, method_t m, request_flags flags)
2300
 {
2301
     StoreEntry *e;
2302
@@ -640,6 +643,10 @@ clientRedirectDone(void *data, char *res
2303
     if (urlgroup && *urlgroup)
2304
 	http->request->urlgroup = xstrdup(urlgroup);
2305
     clientInterpretRequestHeaders(http);
2306
+#if HS_FEAT_ICAP
2307
+    if (Config.icapcfg.onoff)
2308
+	icapCheckAcl(http);
2309
+#endif
2310
 #if HEADERS_LOG
2311
     headersLog(0, 1, request->method, request);
2312
 #endif
2313
@@ -1368,11 +1375,22 @@ httpRequestFree(void *data)
2314
     /* Unlink us from the clients request list */
2315
     dlinkDelete(&http->node, &http->conn->reqs);
2316
     dlinkDelete(&http->active, &ClientActiveRequests);
2317
+#if HS_FEAT_ICAP
2318
+    /*In the case that the upload of data breaks, we need this code here ....  */
2319
+    if (NULL != http->icap_reqmod) {
2320
+	if (cbdataValid(http->icap_reqmod))
2321
+	    if (http->icap_reqmod->icap_fd > -1) {
2322
+		comm_close(http->icap_reqmod->icap_fd);
2323
+	    }
2324
+	cbdataUnlock(http->icap_reqmod);
2325
+	http->icap_reqmod = NULL;
2326
+    }
2327
+#endif
2328
     cbdataFree(http);
2329
 }
2330
 
2331
 /* This is a handler normally called by comm_close() */
2332
-static void
2333
+void
2334
 connStateFree(int fd, void *data)
2335
 {
2336
     ConnStateData *connState = data;
2337
@@ -1392,8 +1410,9 @@ connStateFree(int fd, void *data)
2338
 	authenticateAuthUserRequestUnlock(connState->auth_user_request);
2339
     connState->auth_user_request = NULL;
2340
     authenticateOnCloseConnection(connState);
2341
+    if (connState->in.buf)
2342
     memFreeBuf(connState->in.size, connState->in.buf);
2343
-    pconnHistCount(0, connState->nrequests);
2344
+/*  pconnHistCount(0, connState->nrequests);*/
2345
     if (connState->pinning.fd >= 0)
2346
 	comm_close(connState->pinning.fd);
2347
     cbdataFree(connState);
2348
@@ -1591,7 +1610,7 @@ clientSetKeepaliveFlag(clientHttpRequest
2349
     }
2350
 }
2351
 
2352
-static int
2353
+int
2354
 clientCheckContentLength(request_t * r)
2355
 {
2356
     switch (r->method) {
2357
@@ -1610,7 +1629,7 @@ clientCheckContentLength(request_t * r)
2358
     /* NOT REACHED */
2359
 }
2360
 
2361
-static int
2362
+int
2363
 clientCachable(clientHttpRequest * http)
2364
 {
2365
     request_t *req = http->request;
2366
@@ -1636,7 +1655,7 @@ clientCachable(clientHttpRequest * http)
2367
 }
2368
 
2369
 /* Return true if we can query our neighbors for this object */
2370
-static int
2371
+int
2372
 clientHierarchical(clientHttpRequest * http)
2373
 {
2374
     const char *url = http->uri;
2375
@@ -3302,7 +3321,7 @@ clientProcessRequest2(clientHttpRequest 
2376
     return LOG_TCP_HIT;
2377
 }
2378
 
2379
-static void
2380
+void
2381
 clientProcessRequest(clientHttpRequest * http)
2382
 {
2383
     char *url = http->uri;
2384
@@ -3313,6 +3332,11 @@ clientProcessRequest(clientHttpRequest *
2385
 	RequestMethodStr[r->method],
2386
 	url);
2387
     r->flags.collapsed = 0;
2388
+#if HS_FEAT_ICAP
2389
+    if (clientIcapReqMod(http)) {
2390
+	return;
2391
+    }
2392
+#endif
2393
     if (r->method == METHOD_CONNECT && !http->redirect.status) {
2394
 	http->log_type = LOG_TCP_MISS;
2395
 #if USE_SSL && SSL_CONNECT_INTERCEPT
2396
@@ -3808,6 +3832,20 @@ clientReadRequest(int fd, void *data)
2397
 	    (long) conn->in.offset, (long) conn->in.size);
2398
 	len = conn->in.size - conn->in.offset - 1;
2399
     }
2400
+#if HS_FEAT_ICAP
2401
+    /*
2402
+     * This check exists because ICAP doesn't always work well
2403
+     * with persistent (reused) connections.  One version of the
2404
+     * REQMOD code creates a fake ConnStateData, which doesn't have
2405
+     * an in.buf.  We want to make sure that the fake ConnStateData
2406
+     * doesn't get used here.
2407
+     */
2408
+    if (NULL == conn->in.buf) {
2409
+	debug(33, 1) ("clientReadRequest: FD %d aborted; conn->in.buf is NULL\n", fd);
2410
+	comm_close(fd);
2411
+	return;
2412
+    }
2413
+#endif
2414
     statCounter.syscalls.sock.reads++;
2415
     size = FD_READ_METHOD(fd, conn->in.buf + conn->in.offset, len);
2416
     if (size > 0) {
2417
@@ -3913,6 +3951,8 @@ clientReadRequest(int fd, void *data)
2418
 	    dlinkAddTail(http, &http->node, &conn->reqs);
2419
 	    conn->nrequests++;
2420
 	    commSetTimeout(fd, Config.Timeout.lifetime, clientLifetimeTimeout, http);
2421
+	    F->pconn.uses++;
2422
+            F->pconn.type = 0;
2423
 	    if (parser_return_code < 0) {
2424
 		debug(33, 1) ("clientReadRequest: FD %d (%s:%d) Invalid Request\n", fd, fd_table[fd].ipaddr, fd_table[fd].remote_port);
2425
 		err = errorCon(ERR_INVALID_REQ, HTTP_BAD_REQUEST, NULL);
2426
@@ -4082,7 +4122,7 @@ clientReadRequest(int fd, void *data)
2427
 }
2428
 
2429
 /* file_read like function, for reading body content */
2430
-static void
2431
+void
2432
 clientReadBody(request_t * request, char *buf, size_t size, CBCB * callback, void *cbdata)
2433
 {
2434
     ConnStateData *conn = request->body_reader_data;
2435
@@ -4211,7 +4251,7 @@ clientProcessBody(ConnStateData * conn)
2436
 }
2437
 
2438
 /* Abort a body request */
2439
-static void
2440
+void
2441
 clientAbortBody(request_t * request)
2442
 {
2443
     ConnStateData *conn = request->body_reader_data;
2444
@@ -4253,7 +4293,7 @@ requestTimeout(int fd, void *data)
2445
 	 * Some data has been sent to the client, just close the FD
2446
 	 */
2447
 	comm_close(fd);
2448
-    } else if (conn->nrequests) {
2449
+    } else if (fd_table[fd].pconn.uses) {
2450
 	/*
2451
 	 * assume its a persistent connection; just close it
2452
 	 */
2453
@@ -4974,6 +5014,52 @@ varyEvaluateMatch(StoreEntry * entry, re
2454
 	}
2455
     }
2456
 }
2457
+
2458
+#if HS_FEAT_ICAP
2459
+static int
2460
+clientIcapReqMod(clientHttpRequest * http)
2461
+{
2462
+    ErrorState *err;
2463
+    icap_service *service;
2464
+    if (http->flags.did_icap_reqmod)
2465
+	return 0;
2466
+    if (NULL == (service = icapService(ICAP_SERVICE_REQMOD_PRECACHE, http->request)))
2467
+	return 0;
2468
+    debug(33, 3) ("clientIcapReqMod: calling icapReqModStart for %p\n", http);
2469
+    /*
2470
+     * Note, we pass 'start' and 'log_addr' to ICAP so the access.log
2471
+     * entry comes out right.  The 'clientHttpRequest' created by
2472
+     * the ICAP side is the one that gets logged.  The first
2473
+     * 'clientHttpRequest' does not get logged because its out.size
2474
+     * is zero and log_type is unset.
2475
+     */
2476
+    http->icap_reqmod = icapReqModStart(service,
2477
+	http->uri,
2478
+	http->request,
2479
+	http->conn->fd,
2480
+	http->start,
2481
+	http->conn->log_addr,
2482
+	(void *) http->conn);
2483
+    if (NULL == http->icap_reqmod) {
2484
+	return 0;
2485
+    } else if (-1 == (int) http->icap_reqmod) {
2486
+	/* produce error */
2487
+	http->icap_reqmod = NULL;
2488
+	debug(33, 2) ("clientIcapReqMod: icap told us to send an error\n");
2489
+	http->log_type = LOG_TCP_DENIED;
2490
+	err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR, http->orig_request);
2491
+	err->xerrno = ETIMEDOUT;
2492
+	err->request = requestLink(http->request);
2493
+	err->src_addr = http->conn->peer.sin_addr;
2494
+	http->entry = clientCreateStoreEntry(http, http->request->method, null_request_flags);
2495
+	errorAppendEntry(http->entry, err);
2496
+	return 1;
2497
+    }
2498
+    cbdataLock(http->icap_reqmod);
2499
+    http->flags.did_icap_reqmod = 1;
2500
+    return 1;
2501
+}
2502
+#endif
2503
 
2504
 /* This is a handler normally called by comm_close() */
2505
 static void
2506
Index: src/comm.c
2507
===================================================================
2508
RCS file: /cvsroot/squid/squid/src/comm.c,v
2509
retrieving revision 1.49
2510
retrieving revision 1.29.10.9
2511
diff -p -u -b -r1.49 -r1.29.10.9
2512
--- src/comm.c	23 Oct 2006 11:52:53 -0000	1.49
2513
+++ src/comm.c	3 Nov 2006 18:47:12 -0000	1.29.10.9
2514
@@ -742,8 +742,8 @@ comm_close(int fd)
2515
     F->flags.closing = 1;
2516
     CommWriteStateCallbackAndFree(fd, COMM_ERR_CLOSING);
2517
     commCallCloseHandlers(fd);
2518
-    if (F->uses)		/* assume persistent connect count */
2519
-	pconnHistCount(1, F->uses);
2520
+    if (F->pconn.uses)
2521
+	pconnHistCount(F->pconn.type, F->pconn.uses);
2522
 #if USE_SSL
2523
     if (F->ssl) {
2524
 	if (!F->flags.close_request) {
2525
Index: src/enums.h
2526
===================================================================
2527
RCS file: /cvsroot/squid/squid/src/enums.h,v
2528
retrieving revision 1.57
2529
retrieving revision 1.45.4.6
2530
diff -p -u -b -r1.57 -r1.45.4.6
2531
--- src/enums.h	30 Sep 2006 21:52:28 -0000	1.57
2532
+++ src/enums.h	3 Nov 2006 18:47:13 -0000	1.45.4.6
2533
@@ -93,6 +93,7 @@ typedef enum {
2534
     ERR_ONLY_IF_CACHED_MISS,	/* failure to satisfy only-if-cached request */
2535
     ERR_TOO_BIG,
2536
     TCP_RESET,
2537
+    ERR_ICAP_FAILURE,
2538
     ERR_INVALID_RESP,
2539
     ERR_MAX
2540
 } err_type;
2541
@@ -455,6 +456,9 @@ typedef enum {
2542
     PROTO_WHOIS,
2543
     PROTO_INTERNAL,
2544
     PROTO_HTTPS,
2545
+#if HS_FEAT_ICAP
2546
+    PROTO_ICAP,
2547
+#endif
2548
     PROTO_MAX
2549
 } protocol_t;
2550
 
2551
@@ -630,6 +634,12 @@ typedef enum {
2552
 #if USE_SSL
2553
     MEM_ACL_CERT_DATA,
2554
 #endif
2555
+#if HS_FEAT_ICAP
2556
+    MEM_ICAP_OPT_DATA,
2557
+    MEM_ICAP_SERVICE_LIST,
2558
+    MEM_ICAP_CLASS,
2559
+    MEM_ICAP_ACCESS,
2560
+#endif
2561
     MEM_MAX
2562
 } mem_type;
2563
 
2564
@@ -730,9 +740,14 @@ typedef enum {
2565
     CBDATA_RemovalPolicyWalker,
2566
     CBDATA_RemovalPurgeWalker,
2567
     CBDATA_store_client,
2568
+#ifdef HS_FEAT_ICAP
2569
+    CBDATA_IcapStateData,
2570
+    CBDATA_icap_service,
2571
+#endif
2572
     CBDATA_FIRST_CUSTOM_TYPE = 1000
2573
 } cbdata_type;
2574
 
2575
+
2576
 /*
2577
  * Return codes from checkVary(request)
2578
  */
2579
@@ -781,4 +796,68 @@ typedef enum {
2580
     ST_OP_CREATE
2581
 } store_op_t;
2582
 
2583
+#if HS_FEAT_ICAP
2584
+typedef enum {
2585
+    ICAP_STATUS_NONE = 0,
2586
+    ICAP_STATUS_CONTINUE = 100,
2587
+    ICAP_STATUS_SWITCHING_PROTOCOLS = 101,
2588
+    ICAP_STATUS_STATUS_OK = 200,
2589
+    ICAP_CREATED = 201,
2590
+    ICAP_STATUS_ACCEPTED = 202,
2591
+    ICAP_STATUS_NON_AUTHORITATIVE_INFORMATION = 203,
2592
+    ICAP_STATUS_NO_MODIFICATION_NEEDED = 204,
2593
+    ICAP_STATUS_RESET_CONTENT = 205,
2594
+    ICAP_STATUS_PARTIAL_CONTENT = 206,
2595
+    ICAP_STATUS_MULTIPLE_CHOICES = 300,
2596
+    ICAP_STATUS_MOVED_PERMANENTLY = 301,
2597
+    ICAP_STATUS_MOVED_TEMPORARILY = 302,
2598
+    ICAP_STATUS_SEE_OTHER = 303,
2599
+    ICAP_STATUS_NOT_MODIFIED = 304,
2600
+    ICAP_STATUS_USE_PROXY = 305,
2601
+    ICAP_STATUS_BAD_REQUEST = 400,
2602
+    ICAP_STATUS_UNAUTHORIZED = 401,
2603
+    ICAP_STATUS_PAYMENT_REQUIRED = 402,
2604
+    ICAP_STATUS_FORBIDDEN = 403,
2605
+    ICAP_STATUS_SERVICE_NOT_FOUND = 404,
2606
+    ICAP_STATUS_METHOD_NOT_ALLOWED = 405,
2607
+    ICAP_STATUS_NOT_ACCEPTABLE = 406,
2608
+    ICAP_STATUS_PROXY_AUTHENTICATION_REQUIRED = 407,
2609
+    ICAP_STATUS_REQUEST_TIMEOUT = 408,
2610
+    ICAP_STATUS_CONFLICT = 409,
2611
+    ICAP_STATUS_GONE = 410,
2612
+    ICAP_STATUS_LENGTH_REQUIRED = 411,
2613
+    ICAP_STATUS_PRECONDITION_FAILED = 412,
2614
+    ICAP_STATUS_REQUEST_ENTITY_TOO_LARGE = 413,
2615
+    ICAP_STATUS_REQUEST_URI_TOO_LARGE = 414,
2616
+    ICAP_STATUS_UNSUPPORTED_MEDIA_TYPE = 415,
2617
+    ICAP_STATUS_INTERNAL_SERVER_ERROR = 500,
2618
+    ICAP_STATUS_NOT_IMPLEMENTED = 501,
2619
+    ICAP_STATUS_BAD_GATEWAY = 502,
2620
+    ICAP_STATUS_SERVICE_OVERLOADED = 503,
2621
+    ICAP_STATUS_GATEWAY_TIMEOUT = 504,
2622
+    ICAP_STATUS_ICAP_VERSION_NOT_SUPPORTED = 505,
2623
+    ICAP_STATUS_INVALID_HEADER = 600
2624
+} icap_status;
2625
+
2626
+/*
2627
+ * these values are used as index in an array, so it seems to be better to 
2628
+ * assign some numbers
2629
+ */
2630
+typedef enum {
2631
+    ICAP_SERVICE_REQMOD_PRECACHE = 0,
2632
+    ICAP_SERVICE_REQMOD_POSTCACHE = 1,
2633
+    ICAP_SERVICE_RESPMOD_PRECACHE = 2,
2634
+    ICAP_SERVICE_RESPMOD_POSTCACHE = 3,
2635
+    ICAP_SERVICE_MAX = 4
2636
+} icap_service_t;
2637
+
2638
+typedef enum {
2639
+    ICAP_METHOD_NONE,
2640
+    ICAP_METHOD_OPTION,
2641
+    ICAP_METHOD_REQMOD,
2642
+    ICAP_METHOD_RESPMOD
2643
+} icap_method_t;
2644
+
2645
+#endif /* HS_FEAT_ICAP */
2646
+
2647
 #endif /* SQUID_ENUMS_H */
2648
Index: src/forward.c
2649
===================================================================
2650
--- src/forward.c	Tue Apr 17 11:35:17 2007
2651
+++ src/forward.c	Thu May 17 13:08:19 2007
2652
@@ -943,6 +943,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
@@ -981,6 +983,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
@@ -1000,7 +1004,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
--- src/globals.h.orig	Fri Jan 19 01:19:26 2007
2684
+++ src/globals.h	Wed Jan 24 17:15:33 2007
2685
@@ -171,6 +171,9 @@ extern const char *external_acl_message;
2686
 #if HAVE_SBRK
2687
 extern void *sbrk_start;	/* 0 */
2688
 #endif
2689
+#if HS_FEAT_ICAP
2690
+extern const char *icap_service_type_str[];
2691
+#endif
2692
 extern int opt_send_signal;	/* -1 */
2693
 extern int opt_no_daemon;	/* 0 */
2694
 #if LINUX_TPROXY
2695
Index: src/http.c
2696
===================================================================
2697
RCS file: /cvsroot/squid/squid/src/http.c,v
2698
retrieving revision 1.58
2699
retrieving revision 1.28.4.13
2700
diff -p -u -b -r1.58 -r1.28.4.13
2701
--- src/http.c	24 Feb 2007 11:52:43 -0000	1.58
2702
+++ src/http.c	27 Feb 2007 21:57:26 -0000	1.28.4.13
2703
@@ -47,7 +47,7 @@ static CWCB httpSendRequestEntry;
2704
 
2705
 static PF httpReadReply;
2706
 static void httpSendRequest(HttpStateData *);
2707
-static PF httpStateFree;
2708
+PF httpStateFree;
2709
 static PF httpTimeout;
2710
 static void httpCacheNegatively(StoreEntry *);
2711
 static void httpMakePrivate(StoreEntry *);
2712
@@ -56,11 +56,12 @@ static int httpCachableReply(HttpStateDa
2713
 static void httpMaybeRemovePublic(StoreEntry *, http_status);
2714
 static int peer_supports_connection_pinning(HttpStateData * httpState);
2715
 
2716
-static void
2717
+void
2718
 httpStateFree(int fd, void *data)
2719
 {
2720
     HttpStateData *httpState = data;
2721
 #if DELAY_POOLS
2722
+    if (fd >= 0)
2723
     delayClearNoDelay(fd);
2724
 #endif
2725
     if (httpState == NULL)
2726
@@ -81,6 +82,9 @@ httpStateFree(int fd, void *data)
2727
     httpState->request = NULL;
2728
     httpState->orig_request = NULL;
2729
     stringClean(&httpState->chunkhdr);
2730
+#if HS_FEAT_ICAP
2731
+    cbdataUnlock(httpState->icap_writer);
2732
+#endif
2733
     cbdataFree(httpState);
2734
 }
2735
 
2736
@@ -410,7 +414,7 @@ httpMakeVaryMark(request_t * request, Ht
2737
 }
2738
 
2739
 /* rewrite this later using new interfaces @?@ */
2740
-static size_t
2741
+size_t
2742
 httpProcessReplyHeader(HttpStateData * httpState, const char *buf, int size)
2743
 {
2744
     StoreEntry *entry = httpState->entry;
2745
@@ -640,11 +644,25 @@ httpAppendBody(HttpStateData * httpState
2746
 	    if (size > httpState->chunk_size)
2747
 		size = httpState->chunk_size;
2748
 	    httpState->chunk_size -= size;
2749
+#ifdef HS_FEAT_ICAP
2750
+	    if (httpState->icap_writer) {
2751
+		debug(81, 5) ("calling icapRespModAddBodyData from %s:%d\n", __FILE__, __LINE__);
2752
+		icapRespModAddBodyData(httpState->icap_writer, buf, size);
2753
+		httpState->icap_writer->fake_content_length += size;
2754
+	    } else
2755
+#endif
2756
 	    storeAppend(httpState->entry, buf, size);
2757
 	    buf += size;
2758
 	    len -= size;
2759
 	} else if (httpState->chunk_size < 0) {
2760
 	    /* non-chunked without content-length */
2761
+#ifdef HS_FEAT_ICAP
2762
+	     if (httpState->icap_writer) {
2763
+		 debug(81, 5) ("calling icapRespModAddBodyData from %s:%d\n", __FILE__, __LINE__);
2764
+		 icapRespModAddBodyData(httpState->icap_writer, buf, len);
2765
+		 httpState->icap_writer->fake_content_length += len;
2766
+	     } else
2767
+#endif	     
2768
 	    storeAppend(httpState->entry, buf, len);
2769
 	    len = 0;
2770
 	} else if (httpState->flags.chunked) {
2771
@@ -699,6 +717,15 @@ httpAppendBody(HttpStateData * httpState
2772
 	    /* Don't know what to do with this data. Bail out */
2773
 	    break;
2774
 	}
2775
+#if HS_FEAT_ICAP
2776
+	if (httpState->icap_writer) {
2777
+	    if (!httpState->icap_writer->respmod.entry) {
2778
+		debug(11, 3) ("httpReadReply: FD: %d: icap respmod aborded!\n", fd);
2779
+		comm_close(fd);
2780
+		return;
2781
+	    }
2782
+	} else
2783
+#endif
2784
 	if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
2785
 	    /*
2786
 	     * the above storeAppend() call could ABORT this entry,
2787
@@ -720,6 +747,10 @@ httpAppendBody(HttpStateData * httpState
2788
     if (!httpState->chunk_size && !httpState->flags.chunked)
2789
 	complete = 1;
2790
     if (!complete && len == 0) {
2791
+#ifdef HS_FEAT_ICAP
2792
+    if (httpState->icap_writer)
2793
+	icapSendRespMod(httpState->icap_writer, 0);
2794
+#endif
2795
 	/* Wait for more data or EOF condition */
2796
 	if (httpState->flags.keepalive_broken) {
2797
 	    commSetTimeout(fd, 10, NULL, NULL);
2798
@@ -779,6 +810,10 @@ httpAppendBody(HttpStateData * httpState
2799
      */
2800
     if (!entry->mem_obj->reply->keep_alive)
2801
 	keep_alive = 0;
2802
+#ifdef HS_FEAT_ICAP
2803
+    if (httpState->icap_writer)
2804
+	icapSendRespMod(httpState->icap_writer, 1);
2805
+#endif
2806
     if (keep_alive) {
2807
 	int pinned = 0;
2808
 #if LINUX_TPROXY
2809
@@ -838,6 +873,17 @@ httpReadReply(int fd, void *data)
2810
 #endif
2811
     int buffer_filled;
2812
 
2813
+#if HS_FEAT_ICAP
2814
+    if (httpState->icap_writer) {
2815
+	if (!httpState->icap_writer->respmod.entry) {
2816
+	    debug(11, 3) ("httpReadReply: FD: %d: icap respmod aborded!\n", fd);
2817
+	    comm_close(fd);
2818
+	    return;
2819
+	}
2820
+	/*The folowing entry can not be marked as aborted.  
2821
+	 * The StoreEntry icap_writer->respmod.entry used when the icap_write used...... */
2822
+    } else
2823
+#endif
2824
     if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
2825
 	comm_close(fd);
2826
 	return;
2827
@@ -849,7 +895,35 @@ httpReadReply(int fd, void *data)
2828
     else
2829
 	delay_id = delayMostBytesAllowed(entry->mem_obj, &read_sz);
2830
 #endif
2831
+#if HS_FEAT_ICAP
2832
+    if (httpState->icap_writer) {
2833
+	IcapStateData *icap = httpState->icap_writer;
2834
+	/*
2835
+	 * Ok we have a received a response from the web server, so try to 
2836
+	 * connect the icap server if it's the first attemps. If we try
2837
+	 * to connect to the icap server, defer this request (do not read
2838
+	 * the buffer), and defer until icapConnectOver() is not called.
2839
+	 */
2840
+	if (icap->flags.connect_requested == 0) {
2841
+	    debug(81, 2) ("icapSendRespMod: Create a new connection to icap server\n");
2842
+	    if (!icapConnect(icap, icapConnectOver)) {
2843
+		debug(81, 2) ("icapSendRespMod: Something strange while creating a socket to icap server\n");
2844
+		commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
2845
+		return;
2846
+	    }
2847
+	    debug(81, 2) ("icapSendRespMod: new connection to icap server (using FD=%d)\n", icap->icap_fd);
2848
+	    icap->flags.connect_requested = 1;
2849
+	    /* Wait for more data or EOF condition */
2850
+	    commSetTimeout(fd, httpState->flags.keepalive_broken ? 10 : Config.Timeout.read, NULL, NULL);
2851
+	    commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
2852
+	    return;
2853
+	}
2854
 
2855
+       if(icap->flags.no_content == 1) {
2856
+	 commSetDefer(fd, fwdCheckDeferRead, icap->respmod.entry);
2857
+       }
2858
+    }
2859
+#endif
2860
     errno = 0;
2861
     statCounter.syscalls.sock.reads++;
2862
     len = FD_READ_METHOD(fd, buf, read_sz);
2863
@@ -868,7 +942,13 @@ httpReadReply(int fd, void *data)
2864
 	IOStats.Http.read_hist[bin]++;
2865
 	buf[len] = '\0';
2866
     }
2867
-    if (!httpState->reply_hdr.size && len > 0 && fd_table[fd].uses > 1) {
2868
+#ifdef HS_FEAT_ICAP
2869
+    if (httpState->icap_writer)
2870
+	(void) 0;
2871
+    else
2872
+#endif
2873
+
2874
+    if (!httpState->reply_hdr.size && len > 0 && fd_table[fd].pconn.uses > 1) {
2875
 	/* Skip whitespace */
2876
 	while (len > 0 && xisspace(*buf))
2877
 	    xmemmove(buf, buf + 1, len--);
2878
@@ -971,12 +1051,49 @@ httpReadReply(int fd, void *data)
2879
 		commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
2880
 		return;
2881
 	    }
2882
+#ifdef HS_FEAT_ICAP
2883
+	    if (httpState->icap_writer) {
2884
+		debug(81, 5) ("calling icapSendRespMod from %s:%d\n", __FILE__, __LINE__);
2885
+		if (cbdataValid(httpState->icap_writer)) {
2886
+		    icapRespModAddResponceHeaders(httpState->icap_writer, buf, done);
2887
+		    httpState->icap_writer->fake_content_length += done;
2888
+		}
2889
+	    }
2890
+#endif
2891
 	}
2892
 	httpAppendBody(httpState, buf + done, len - done, buffer_filled);
2893
 	return;
2894
     }
2895
 }
2896
 
2897
+#ifdef HS_FEAT_ICAP
2898
+static int
2899
+httpReadReplyWaitForIcap(int fd, void *data)
2900
+{
2901
+    HttpStateData *httpState = data;
2902
+    if (NULL == httpState->icap_writer)
2903
+	return 0;
2904
+    /* 
2905
+     * Do not defer when we are not connected to the icap server.
2906
+     * Defer when the icap server connection is not established but pending
2907
+     * Defer when the icap server is busy (writing on the socket)
2908
+     */
2909
+    debug(11, 5) ("httpReadReplyWaitForIcap: FD %d, connect_requested=%d\n",
2910
+	fd, httpState->icap_writer->flags.connect_requested);
2911
+    if (!httpState->icap_writer->flags.connect_requested)
2912
+	return 0;
2913
+    debug(11, 5) ("httpReadReplyWaitForIcap: FD %d, connect_pending=%d\n",
2914
+	fd, httpState->icap_writer->flags.connect_pending);
2915
+    if (httpState->icap_writer->flags.connect_pending)
2916
+	return 1;
2917
+    debug(11, 5) ("httpReadReplyWaitForIcap: FD %d, write_pending=%d\n",
2918
+	fd, httpState->icap_writer->flags.write_pending);
2919
+    if (httpState->icap_writer->flags.write_pending)
2920
+	return 1;
2921
+    return 0;
2922
+}
2923
+#endif
2924
+
2925
 /* This will be called when request write is complete. Schedule read of
2926
  * reply. */
2927
 static void
2928
@@ -1004,6 +1121,63 @@ httpSendComplete(int fd, char *bufnotuse
2929
 	comm_close(fd);
2930
 	return;
2931
     } else {
2932
+	/* Schedule read reply. */
2933
+#ifdef HS_FEAT_ICAP
2934
+	if (icapService(ICAP_SERVICE_RESPMOD_PRECACHE, httpState->orig_request)) {
2935
+	    httpState->icap_writer = icapRespModStart(
2936
+		ICAP_SERVICE_RESPMOD_PRECACHE,
2937
+		httpState->orig_request, httpState->entry, httpState->flags);
2938
+	    if (-1 == (int) httpState->icap_writer) {
2939
+		/* TODO: send error here and exit */
2940
+		ErrorState *err;
2941
+		httpState->icap_writer = 0;
2942
+		err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR, httpState->fwd->request);
2943
+		err->xerrno = errno;
2944
+		err->request = requestLink(httpState->orig_request);
2945
+		errorAppendEntry(entry, err);
2946
+		comm_close(fd);
2947
+		return;
2948
+	    } else if (httpState->icap_writer) {
2949
+		request_flags fake_flags = httpState->orig_request->flags;
2950
+		method_t fake_method = entry->mem_obj->method;
2951
+		const char *fake_msg = "this is a fake entry for "
2952
+		" response sent to an ICAP RESPMOD server";
2953
+		cbdataLock(httpState->icap_writer);
2954
+		/*
2955
+		 * this httpState will give the data it reads to
2956
+		 * the icap server, rather than put it into
2957
+		 * a StoreEntry
2958
+		 */
2959
+		storeUnregisterAbort(httpState->entry);
2960
+		storeUnlockObject(httpState->entry);
2961
+		/*
2962
+		 * create a bogus entry because the code assumes one is
2963
+		 * always there.
2964
+		 */
2965
+		fake_flags.cachable = 0;
2966
+		fake_flags.hierarchical = 0;	/* force private key */
2967
+		httpState->entry = storeCreateEntry("fake", "fake", fake_flags, fake_method);
2968
+		storeAppend(httpState->entry, fake_msg, strlen(fake_msg));
2969
+		/*
2970
+		 * pull a switcheroo on fwdState->entry.
2971
+		 */
2972
+		storeUnlockObject(httpState->fwd->entry);
2973
+		httpState->fwd->entry = httpState->entry;
2974
+		storeLockObject(httpState->fwd->entry);
2975
+		/*
2976
+		 * Note that we leave fwdState connected to httpState,
2977
+		 * but we changed the entry.  So when fwdComplete
2978
+		 * or whatever is called it does no harm -- its
2979
+		 * just the fake entry.
2980
+		 */
2981
+	    } else {
2982
+		/*
2983
+		 * failed to open connection to ICAP server. 
2984
+		 * But bypass request, so just continue here.
2985
+		 */
2986
+	    }
2987
+	}
2988
+#endif
2989
 	/*
2990
 	 * Set the read timeout here because it hasn't been set yet.
2991
 	 * We only set the read timeout after the request has been
2992
@@ -1012,8 +1186,18 @@ httpSendComplete(int fd, char *bufnotuse
2993
 	 * the timeout for POST/PUT requests that have very large
2994
 	 * request bodies.
2995
 	 */
2996
+
2997
+	/* removed in stable5:
2998
+	 * commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
2999
+	 */
3000
 	commSetTimeout(fd, Config.Timeout.read, httpTimeout, httpState);
3001
-	commSetDefer(fd, fwdCheckDeferRead, entry);
3002
+#ifdef HS_FEAT_ICAP
3003
+	if (httpState->icap_writer) {
3004
+	    debug(11, 5) ("FD %d, setting httpReadReplyWaitForIcap\n", httpState->fd);
3005
+	    commSetDefer(httpState->fd, httpReadReplyWaitForIcap, httpState);
3006
+	} else
3007
+#endif
3008
+	    commSetDefer(httpState->fd, fwdCheckDeferRead, entry);
3009
     }
3010
     httpState->flags.request_sent = 1;
3011
 }
3012
@@ -1317,8 +1501,11 @@ httpBuildRequestHeader(request_t * reque
3013
 	if (!EBIT_TEST(cc->mask, CC_MAX_AGE)) {
3014
 	    const char *url = entry ? storeUrl(entry) : urlCanonical(orig_request);
3015
 	    httpHdrCcSetMaxAge(cc, getMaxAge(url));
3016
+#ifndef HS_FEAT_ICAP
3017
+	    /* Don;t bother - if  the url you want to cache is redirected? */
3018
 	    if (strLen(request->urlpath))
3019
 		assert(strstr(url, strBuf(request->urlpath)));
3020
+#endif
3021
 	}
3022
 	/* Set no-cache if determined needed but not found */
3023
 	if (orig_request->flags.nocache && !httpHeaderHas(hdr_in, HDR_PRAGMA))
3024
@@ -1444,6 +1631,7 @@ httpStart(FwdState * fwd)
3025
     int fd = fwd->server_fd;
3026
     HttpStateData *httpState;
3027
     request_t *proxy_req;
3028
+    /* ErrorState *err; */
3029
     request_t *orig_req = fwd->request;
3030
     debug(11, 3) ("httpStart: \"%s %s\"\n",
3031
 	RequestMethodStr[orig_req->method],
3032
@@ -1486,12 +1674,22 @@ httpStart(FwdState * fwd)
3033
 	httpState->request = requestLink(orig_req);
3034
 	httpState->orig_request = requestLink(orig_req);
3035
     }
3036
+#ifdef HS_FEAT_ICAP
3037
+    if (icapService(ICAP_SERVICE_REQMOD_POSTCACHE, httpState->orig_request)) {
3038
+	httpState->icap_writer = icapRespModStart(ICAP_SERVICE_REQMOD_POSTCACHE,
3039
+	    httpState->orig_request, httpState->entry, httpState->flags);
3040
+	if (httpState->icap_writer) {
3041
+	    return;
3042
+	}
3043
+    }
3044
+#endif
3045
     /*
3046
      * register the handler to free HTTP state data when the FD closes
3047
      */
3048
     comm_add_close_handler(fd, httpStateFree, httpState);
3049
     statCounter.server.all.requests++;
3050
     statCounter.server.http.requests++;
3051
+
3052
     httpSendRequest(httpState);
3053
     /*
3054
      * We used to set the read timeout here, but not any more.
3055
Index: src/icap_common.c
3056
===================================================================
3057
RCS file: src/icap_common.c
3058
diff -N src/icap_common.c
3059
--- /dev/null	1 Jan 1970 00:00:00 -0000
3060
+++ src/icap_common.c	26 May 2006 19:24:02 -0000	1.1.14.3
3061
@@ -0,0 +1,815 @@
3062
+/*
3063
+ * $Id$
3064
+ *
3065
+ * DEBUG: section 81    Internet Content Adaptation Protocol (ICAP) Client
3066
+ * AUTHOR: Geetha Manjunath, Hewlett Packard Company
3067
+ *
3068
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
3069
+ * ----------------------------------------------------------
3070
+ *
3071
+ *  Squid is the result of efforts by numerous individuals from
3072
+ *  the Internet community; see the CONTRIBUTORS file for full
3073
+ *  details.   Many organizations have provided support for Squid's
3074
+ *  development; see the SPONSORS file for full details.  Squid is
3075
+ *  Copyrighted (C) 2001 by the Regents of the University of
3076
+ *  California; see the COPYRIGHT file for full details.  Squid
3077
+ *  incorporates software developed and/or copyrighted by other
3078
+ *  sources; see the CREDITS file for full details.
3079
+ *
3080
+ *  This program is free software; you can redistribute it and/or modify
3081
+ *  it under the terms of the GNU General Public License as published by
3082
+ *  the Free Software Foundation; either version 2 of the License, or
3083
+ *  (at your option) any later version.
3084
+ *  
3085
+ *  This program is distributed in the hope that it will be useful,
3086
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
3087
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
3088
+ *  GNU General Public License for more details.
3089
+ *  
3090
+ *  You should have received a copy of the GNU General Public License
3091
+ *  along with this program; if not, write to the Free Software
3092
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
3093
+ *
3094
+ */
3095
+
3096
+/* _GNU_SOURCE is required for strcasestr */
3097
+#define _GNU_SOURCE 1
3098
+
3099
+#include "squid.h"
3100
+#include "util.h"
3101
+
3102
+extern PF httpStateFree;
3103
+
3104
+#define EXPECTED_ICAP_HEADER_LEN 256
3105
+#define ICAP_OPTIONS_REQUEST
3106
+
3107
+
3108
+void
3109
+icapInit()
3110
+{
3111
+#ifdef ICAP_OPTIONS_REQUEST
3112
+    if (Config.icapcfg.onoff) {
3113
+	icapOptInit();
3114
+    }
3115
+#endif
3116
+}
3117
+
3118
+void
3119
+icapClose()
3120
+{
3121
+    icapOptShutdown();
3122
+}
3123
+
3124
+/*
3125
+ * search for a HTTP-like header in the buffer. 
3126
+ * Note, buf must be 0-terminated
3127
+ *
3128
+ * This function is not very good.  It should probably look for
3129
+ * header tokens only at the start of a line, not just anywhere in
3130
+ * the buffer.
3131
+ */
3132
+int
3133
+icapFindHeader(const char *buf, const char *hdr, const char **Start,
3134
+    const char **End)
3135
+{
3136
+    const char *start = NULL;
3137
+    const char *end = NULL;
3138
+    start = strcasestr(buf, hdr);
3139
+    if (NULL == start)
3140
+	return 0;
3141
+    end = start + strcspn(start, "\r\n");
3142
+    if (start == end)
3143
+	return 0;
3144
+    *Start = start;
3145
+    *End = end;
3146
+    return 1;
3147
+}
3148
+
3149
+/* 
3150
+ * parse the contents of the encapsulated header (buffer between enc_start
3151
+ * and enc_end) and put the result into IcapStateData
3152
+ */
3153
+void
3154
+icapParseEncapsulated(IcapStateData * icap, const char *enc_start,
3155
+    const char *enc_end)
3156
+{
3157
+    char *current, *end;
3158
+
3159
+    assert(icap);
3160
+    assert(enc_start);
3161
+    assert(enc_end);
3162
+
3163
+    current = strchr(enc_start, ':');
3164
+    current++;
3165
+    while (current < enc_end) {
3166
+	while (isspace(*current))
3167
+	    current++;
3168
+	if (!strncmp(current, "res-hdr=", 8)) {
3169
+	    current += 8;
3170
+	    icap->enc.res_hdr = strtol(current, &end, 10);
3171
+	} else if (!strncmp(current, "req-hdr=", 8)) {
3172
+	    current += 8;
3173
+	    icap->enc.req_hdr = strtol(current, &end, 10);
3174
+	} else if (!strncmp(current, "null-body=", 10)) {
3175
+	    current += 10;
3176
+	    icap->enc.null_body = strtol(current, &end, 10);
3177
+	} else if (!strncmp(current, "res-body=", 9)) {
3178
+	    current += 9;
3179
+	    icap->enc.res_body = strtol(current, &end, 10);
3180
+	} else if (!strncmp(current, "req-body=", 9)) {
3181
+	    current += 9;
3182
+	    icap->enc.req_body = strtol(current, &end, 10);
3183
+	} else if (!strncmp(current, "opt-body=", 9)) {
3184
+	    current += 9;
3185
+	    icap->enc.opt_body = strtol(current, &end, 10);
3186
+	} else {
3187
+	    /* invalid header */
3188
+	    debug(81, 5) ("icapParseEncapsulated: error in: %s\n", current);
3189
+	    return;
3190
+	}
3191
+	current = end;
3192
+	current = strchr(current, ',');
3193
+	if (current == NULL)
3194
+	    break;
3195
+	else
3196
+	    current++;		/* skip ',' */
3197
+    }
3198
+    debug(81,
3199
+	3) ("icapParseEncapsulated: res-hdr=%d, req-hdr=%d, null-body=%d, "
3200
+	"res-body=%d, req-body=%d, opt-body=%d\n", icap->enc.res_hdr,
3201
+	icap->enc.req_hdr, icap->enc.null_body, icap->enc.res_body,
3202
+	icap->enc.req_body, icap->enc.opt_body);
3203
+
3204
+}
3205
+
3206
+icap_service *
3207
+icapService(icap_service_t type, request_t * r)
3208
+{
3209
+    icap_service_list *isl_iter;
3210
+    int is_iter;
3211
+    int nb_unreachable = 0;
3212
+    icap_service *unreachable_one = NULL;
3213
+
3214
+    debug(81, 8) ("icapService: type=%s\n", icapServiceToStr(type));
3215
+    if (NULL == r) {
3216
+	debug(81, 8) ("icapService: no request_t\n");
3217
+	return NULL;
3218
+    }
3219
+    if (NULL == r->class) {
3220
+	debug(81, 8) ("icapService: no class\n");
3221
+	return NULL;
3222
+    }
3223
+    for (isl_iter = r->class->isl; isl_iter; isl_iter = isl_iter->next) {
3224
+	/* TODO:luc: Do a round-robin, choose a random value ? 
3225
+	 * For now, we use a simple round robin with checking is the
3226
+	 * icap server is available */
3227
+	is_iter = isl_iter->last_service_used;
3228
+	do {
3229
+	    is_iter = (is_iter + 1) % isl_iter->nservices;
3230
+	    debug(81, 8) ("icapService: checking service %s/id=%d\n",
3231
+		isl_iter->services[is_iter]->name, is_iter);
3232
+	    if (type == isl_iter->services[is_iter]->type) {
3233
+		if (!isl_iter->services[is_iter]->unreachable) {
3234
+		    debug(81, 8) ("icapService: found service %s/id=%d\n",
3235
+			isl_iter->services[is_iter]->name, is_iter);
3236
+		    isl_iter->last_service_used = is_iter;
3237
+		    return isl_iter->services[is_iter];
3238
+		}
3239
+		debug(81,
3240
+		    8)
3241
+		    ("icapService: found service %s/id=%d, but it's unreachable. I don't want to use it\n",
3242
+		    isl_iter->services[is_iter]->name, is_iter);
3243
+		unreachable_one = isl_iter->services[is_iter];
3244
+		nb_unreachable++;
3245
+		/* FIXME:luc: in response mod, if we return an NULL pointer, user can bypass
3246
+		 * the filter, is it normal ? */
3247
+	    }
3248
+	} while (is_iter != isl_iter->last_service_used);
3249
+    }
3250
+    debug(81, 8) ("icapService: no service found\n");
3251
+    isl_iter = r->class->isl;
3252
+
3253
+    if (nb_unreachable > 0) {
3254
+	debug(81,
3255
+	    8)
3256
+	    ("All the services are unreachable, returning an unreachable one\n");
3257
+	return unreachable_one;
3258
+    } else {
3259
+	return NULL;
3260
+    }
3261
+}
3262
+
3263
+int
3264
+icapConnect(IcapStateData * icap, CNCB * theCallback)
3265
+{
3266
+    int rc;
3267
+    icap->icap_fd = pconnPop(icap->current_service->hostname,
3268
+	icap->current_service->port, NULL, NULL, 0);
3269
+    if (icap->icap_fd >= 0) {
3270
+	debug(81, 3) ("icapConnect: reused pconn FD %d\n", icap->icap_fd);
3271
+	fd_note(icap->icap_fd, icap->current_service->uri);
3272
+	comm_add_close_handler(icap->icap_fd, icapStateFree, icap);
3273
+	theCallback(icap->icap_fd, 0, icap);
3274
+	return 1;
3275
+    }
3276
+    icap->icap_fd = comm_open(SOCK_STREAM, 0, getOutgoingAddr(NULL), 0,
3277
+	COMM_NONBLOCKING, icap->current_service->uri);
3278
+    debug(81, 5) ("icapConnect: new socket, FD %d, local address %s\n",
3279
+	icap->icap_fd, inet_ntoa(getOutgoingAddr(NULL)));
3280
+    if (icap->icap_fd < 0) {
3281
+	icapStateFree(-1, icap);	/* XXX test */
3282
+	return 0;
3283
+    }
3284
+    icap->flags.connect_pending = 1;
3285
+    /*
3286
+     * Configure timeout and close handler before calling
3287
+     * connect because commConnectStart() might get an error
3288
+     * immediately and close the descriptor before it returns.
3289
+     */
3290
+    commSetTimeout(icap->icap_fd, Config.Timeout.connect,
3291
+	icapConnectTimeout, icap);
3292
+    comm_add_close_handler(icap->icap_fd, icapStateFree, icap);
3293
+    /*
3294
+     * This sucks.  commConnectStart() may fail before returning,
3295
+     * so lets lock the data and check its validity afterwards.
3296
+     */
3297
+    cbdataLock(icap);
3298
+    commConnectStart(icap->icap_fd,
3299
+	icap->current_service->hostname,
3300
+	icap->current_service->port, theCallback, icap);
3301
+    rc = cbdataValid(icap);
3302
+    cbdataUnlock(icap);
3303
+    debug(81, 3) ("icapConnect: returning %d\n", rc);
3304
+    return rc;
3305
+}
3306
+
3307
+IcapStateData *
3308
+icapAllocate(void)
3309
+{
3310
+    IcapStateData *icap;
3311
+
3312
+    if (!Config.icapcfg.onoff)
3313
+	return 0;
3314
+
3315
+    icap = cbdataAlloc(IcapStateData);
3316
+    icap->icap_fd = -1;
3317
+    icap->enc.res_hdr = -1;
3318
+    icap->enc.res_body = -1;
3319
+    icap->enc.req_hdr = -1;
3320
+    icap->enc.req_body = -1;
3321
+    icap->enc.opt_body = -1;
3322
+    icap->enc.null_body = -1;
3323
+    icap->chunk_size = -1;
3324
+    memBufDefInit(&icap->icap_hdr);
3325
+
3326
+    debug(81, 3) ("New ICAP state\n");
3327
+    return icap;
3328
+}
3329
+
3330
+void
3331
+icapStateFree(int fd, void *data)
3332
+{
3333
+    IcapStateData *icap = data;
3334
+    debug(81, 3) ("icapStateFree: FD %d, icap %p\n", fd, icap);
3335
+    assert(icap);
3336
+    assert(-1 == fd || fd == icap->icap_fd);
3337
+    if (icap->respmod.entry) {
3338
+	/*
3339
+	 * If we got some error on this side (like ECONNRESET)
3340
+	 * we must signal the other side(s) with a storeAbort()
3341
+	 * call.
3342
+	 */
3343
+	if (icap->respmod.entry->store_status != STORE_OK)
3344
+	    storeAbort(icap->respmod.entry);
3345
+	storeUnlockObject(icap->respmod.entry);
3346
+	icap->respmod.entry = NULL;
3347
+    }
3348
+    requestUnlink(icap->request);
3349
+    icap->request = NULL;
3350
+    if (!memBufIsNull(&icap->icap_hdr))
3351
+	memBufClean(&icap->icap_hdr);
3352
+    if (!memBufIsNull(&icap->respmod.buffer))
3353
+	memBufClean(&icap->respmod.buffer);
3354
+    if (!memBufIsNull(&icap->respmod.req_hdr_copy))
3355
+	memBufClean(&icap->respmod.req_hdr_copy);
3356
+    if (!memBufIsNull(&icap->respmod.resp_copy))
3357
+	memBufClean(&icap->respmod.resp_copy);
3358
+    if (!memBufIsNull(&icap->reqmod.hdr_buf))
3359
+	memBufClean(&icap->reqmod.hdr_buf);
3360
+    if (!memBufIsNull(&icap->reqmod.http_entity.buf))
3361
+	memBufClean(&icap->reqmod.http_entity.buf);
3362
+    if (!memBufIsNull(&icap->chunk_buf))
3363
+	memBufClean(&icap->chunk_buf);
3364
+    if (icap->httpState)
3365
+	httpStateFree(-1, icap->httpState);
3366
+    cbdataUnlock(icap->reqmod.client_cookie);
3367
+    cbdataFree(icap);
3368
+}
3369
+
3370
+void
3371
+icapConnectTimeout(int fd, void *data)
3372
+{
3373
+    IcapStateData *icap = data;
3374
+    debug(81, 3) ("icapConnectTimeout: FD %d, unreachable=1\n", fd);
3375
+    assert(fd == icap->icap_fd);
3376
+    icapOptSetUnreachable(icap->current_service);
3377
+    comm_close(fd);
3378
+}
3379
+
3380
+void
3381
+icapReadTimeout(int fd, void *data)
3382
+{
3383
+    IcapStateData *icap = data;
3384
+    assert(fd == icap->icap_fd);
3385
+    if (icap->flags.wait_for_preview_reply || icap->flags.http_server_eof) {
3386
+	debug(81, 3) ("icapReadTimeout: FD %d, unreachable=1\n", fd);
3387
+	icapOptSetUnreachable(icap->current_service);
3388
+    } else
3389
+	debug(81, 3) ("icapReadTimeout: FD %d, still reachable\n", fd);
3390
+    comm_close(fd);
3391
+}
3392
+
3393
+icap_service_t
3394
+icapServiceToType(const char *s)
3395
+{
3396
+    if (!strcmp(s, "reqmod_precache"))
3397
+	return ICAP_SERVICE_REQMOD_PRECACHE;
3398
+    if (!strcmp(s, "reqmod_postcache"))
3399
+	return ICAP_SERVICE_REQMOD_POSTCACHE;
3400
+    if (!strcmp(s, "respmod_precache"))
3401
+	return ICAP_SERVICE_RESPMOD_PRECACHE;
3402
+    if (!strcmp(s, "respmod_postcache"))
3403
+	return ICAP_SERVICE_RESPMOD_POSTCACHE;
3404
+    return ICAP_SERVICE_MAX;
3405
+}
3406
+
3407
+const char *
3408
+icapServiceToStr(const icap_service_t type)
3409
+{
3410
+    if (type >= 0 && type < ICAP_SERVICE_MAX)
3411
+	return icap_service_type_str[type];
3412
+    else
3413
+	return "error";
3414
+}
3415
+
3416
+
3417
+/* copied from clientAclChecklistCreate */
3418
+static aclCheck_t *
3419
+icapAclChecklistCreate(const acl_access * acl, const clientHttpRequest * http)
3420
+{
3421
+    aclCheck_t *ch;
3422
+    ConnStateData *conn = http->conn;
3423
+    ch = aclChecklistCreate(acl, http->request, 0);
3424
+    ch->conn = conn;
3425
+    cbdataLock(ch->conn);
3426
+    return ch;
3427
+}
3428
+
3429
+/*
3430
+ * check wether we do icap for a request
3431
+ */
3432
+int
3433
+icapCheckAcl(clientHttpRequest * http)
3434
+{
3435
+    icap_access *iter;
3436
+    aclCheck_t *icapChecklist;
3437
+
3438
+    for (iter = Config.icapcfg.access_head; iter; iter = iter->next) {
3439
+	acl_access *A = iter->access;
3440
+	icapChecklist = icapAclChecklistCreate(A, http);
3441
+	if (aclMatchAclList(A->acl_list, icapChecklist)) {
3442
+	    debug(81, 5) ("icapCheckAcl: match for class=%s\n",
3443
+		iter->class->name);
3444
+	    if (A->allow) {
3445
+		/* allow rule, do icap and use associated class */
3446
+		http->request->class = iter->class;
3447
+		aclChecklistFree(icapChecklist);
3448
+		return 1;
3449
+	    } else {
3450
+		/* deny rule, stop processing */
3451
+		aclChecklistFree(icapChecklist);
3452
+		return 0;
3453
+	    }
3454
+	}
3455
+	aclChecklistFree(icapChecklist);
3456
+    }
3457
+    return 0;
3458
+}
3459
+
3460
+/* icapLineLength
3461
+ *
3462
+ * returns the amount of data until lineending ( \r\n )
3463
+ * This function is NOT tolerant of variations of \r\n.
3464
+ */
3465
+size_t
3466
+icapLineLength(const char *start, int len)
3467
+{
3468
+    size_t lineLen = 0;
3469
+    char *end = (char *) memchr(start, '\r', len);
3470
+    if (NULL == end)
3471
+	return 0;
3472
+    end++;			/* advance to where '\n' should be */
3473
+    lineLen = end - start + 1;
3474
+    if (lineLen > len) {
3475
+	debug(0, 0) ("icapLineLength: warning lineLen (%d) > len (%d)\n",
3476
+	    lineLen, len);
3477
+	return 0;
3478
+    }
3479
+    if (*end != '\n') {
3480
+	debug(0, 0) ("icapLineLength: warning *end (%x) != '\\n'\n", *end);
3481
+	return 0;
3482
+    }
3483
+    debug(81, 7) ("icapLineLength: returning %d\n", lineLen);
3484
+    return lineLen;
3485
+}
3486
+
3487
+/*
3488
+ * return:
3489
+ *   -1 if EOF before getting end of ICAP header
3490
+ *    0 if we don't have the entire ICAP header yet
3491
+ *    1 if we got the whole header
3492
+ */
3493
+int
3494
+icapReadHeader(int fd, IcapStateData * icap, int *isIcap)
3495
+{
3496
+    int headlen = 0;
3497
+    int len = 0;
3498
+    int peek_sz = EXPECTED_ICAP_HEADER_LEN;
3499
+    int read_sz = 0;
3500
+    LOCAL_ARRAY(char, tmpbuf, SQUID_TCP_SO_RCVBUF);
3501
+    for (;;) {
3502
+	len = recv(fd, tmpbuf, peek_sz, MSG_PEEK);
3503
+	debug(81, 5) ("recv(FD %d, ..., MSG_PEEK) ret %d\n", fd, len);
3504
+	if (len < 0) {
3505
+	    debug(81, 1) ("icapReadHeader: FD %d recv error: %s\n", fd,
3506
+		xstrerror());
3507
+	    return -1;
3508
+	}
3509
+	if (len == 0) {
3510
+	    debug(81, 2) ("icapReadHeader: FD %d recv EOF\n", fd);
3511
+	    return -1;
3512
+	}
3513
+	headlen = headersEnd(tmpbuf, len);
3514
+	debug(81, 3) ("headlen=%d\n", headlen);
3515
+	/*
3516
+	 * break if we now know where the ICAP headers end
3517
+	 */
3518
+	if (headlen)
3519
+	    break;
3520
+	/*
3521
+	 * break if we know there is no more data to read
3522
+	 */
3523
+	if (len < peek_sz)
3524
+	    break;
3525
+	/*
3526
+	 * The ICAP header is larger than (or equal to) our read
3527
+	 * buffer, so double it and try to peek again.
3528
+	 */
3529
+	peek_sz *= 2;
3530
+	if (peek_sz >= SQUID_TCP_SO_RCVBUF) {
3531
+	    debug(81,
3532
+		1) ("icapReadHeader: Failed to find end of ICAP header\n");
3533
+	    debug(81, 1) ("\twithin first %d bytes of response\n",
3534
+		SQUID_TCP_SO_RCVBUF);
3535
+	    debug(81, 1) ("\tpossible persistent connection bug/confusion\n");
3536
+	    return -1;
3537
+	}
3538
+    }
3539
+    /*
3540
+     * Now actually read the data from the kernel
3541
+     */
3542
+    if (headlen)
3543
+	read_sz = headlen;
3544
+    else
3545
+	read_sz = len;
3546
+    len = FD_READ_METHOD(fd, tmpbuf, read_sz);
3547
+    assert(len == read_sz);
3548
+    fd_bytes(fd, len, FD_READ);
3549
+    memBufAppend(&icap->icap_hdr, tmpbuf, len);
3550
+    if (headlen) {
3551
+	/* End of ICAP header found */
3552
+	if (icap->icap_hdr.size < 4)
3553
+	    *isIcap = 0;
3554
+	else if (0 == strncmp(icap->icap_hdr.buf, "ICAP", 4))
3555
+	    *isIcap = 1;
3556
+	else
3557
+	    *isIcap = 0;
3558
+	return 1;
3559
+    }
3560
+    /*
3561
+     * We don't have all the headers yet
3562
+     */
3563
+    return 0;
3564
+}
3565
+
3566
+static int
3567
+icapParseConnectionClose(const IcapStateData * icap, const char *s,
3568
+    const char *e)
3569
+{
3570
+    char *t;
3571
+    char *q;
3572
+    /*
3573
+     * s points to the start of the line "Connection: ... "
3574
+     * e points to *after* the last character on the line
3575
+     */
3576
+    s += 11;			/* skip past Connection: */
3577
+    while (s < e && isspace(*s))
3578
+	s++;
3579
+    if (e - s < 5)
3580
+	return 0;
3581
+    /*
3582
+     * create a buffer that we can use strtok on
3583
+     */
3584
+    t = xmalloc(e - s + 1);
3585
+    strncpy(t, s, e - s);
3586
+    *(t + (e - s)) = '\0';
3587
+    for (q = strtok(t, ","); q; q = strtok(NULL, ",")) {
3588
+	if (0 == strcasecmp(q, "close")) {
3589
+	    xfree(t);
3590
+	    return 1;
3591
+	}
3592
+    }
3593
+    xfree(t);
3594
+    return 0;
3595
+}
3596
+
3597
+/* returns icap status, version and subversion extracted from status line or -1 on parsing failure 
3598
+ * The str_status pointr points to the text returned from the icap server.
3599
+ * sline probably is NOT terminated with '\0' 
3600
+ */
3601
+int
3602
+icapParseStatusLine(const char *sline, int slinesize, int *version_major,
3603
+    int *version_minor, const char **str_status)
3604
+{
3605
+    char *sp, *stmp, *ep = (char *) sline + slinesize;
3606
+    int status;
3607
+    if (slinesize < 14)		/*The format of this line is: "ICAP/x.x xxx[ msg....]\r\n" */
3608
+	return -1;
3609
+
3610
+    if (strncmp(sline, "ICAP/", 5) != 0)
3611
+	return -1;
3612
+    if (sscanf(sline + 5, "%d.%d", version_major, version_minor) != 2)
3613
+	return -1;
3614
+
3615
+    if (!(sp = memchr(sline, ' ', slinesize)))
3616
+	return -1;
3617
+
3618
+    while (sp < ep && xisspace(*++sp));
3619
+
3620
+    if (!xisdigit(*sp) || sp >= ep)
3621
+	return -1;
3622
+
3623
+    if ((status = strtol(sp, &stmp, 10)) <= 0)
3624
+	return -1;
3625
+    sp = stmp;
3626
+
3627
+    while (sp < ep && xisspace(*++sp));
3628
+    *str_status = sp;
3629
+    /*Must add a test for "\r\n" end headers .... */
3630
+    return status;
3631
+}
3632
+
3633
+
3634
+void
3635
+icapSetKeepAlive(IcapStateData * icap, const char *hdrs)
3636
+{
3637
+    const char *start;
3638
+    const char *end;
3639
+    if (0 == icap->flags.keep_alive)
3640
+	return;
3641
+    if (0 == icapFindHeader(hdrs, "Connection:", &start, &end)) {
3642
+	icap->flags.keep_alive = 1;
3643
+	return;
3644
+    }
3645
+    if (icapParseConnectionClose(icap, start, end))
3646
+	icap->flags.keep_alive = 0;
3647
+    else
3648
+	icap->flags.keep_alive = 1;
3649
+}
3650
+
3651
+/*
3652
+ * icapParseChunkSize
3653
+ *
3654
+ * Returns the offset where the next chunk starts
3655
+ * return parameter chunk_size;
3656
+ */
3657
+static int
3658
+icapParseChunkSize(const char *buf, int len, int *chunk_size)
3659
+{
3660
+    int chunkSize = 0;
3661
+    char c;
3662
+    size_t start;
3663
+    size_t end;
3664
+    size_t nextStart = 0;
3665
+    debug(81, 3) ("icapParseChunkSize: buf=%p, len=%d\n", buf, len);
3666
+    do {
3667
+	start = nextStart;
3668
+	debug(81, 3) ("icapParseChunkSize: start=%d\n", start);
3669
+	if (len <= start) {
3670
+	    /*
3671
+	     * end of buffer, so far no lines or only empty lines,
3672
+	     * wait for more data. read chunk size with next buffer.
3673
+	     */
3674
+	    *chunk_size = 0;
3675
+	    return 0;
3676
+	}
3677
+	end = start + icapLineLength(buf + start, len - start);
3678
+	nextStart = end;
3679
+	if (end <= start) {
3680
+	    /*
3681
+	     * no line found, need more code here, now we are in
3682
+	     * deep trouble, buffer stops with half a chunk size
3683
+	     * line. For now stop here.
3684
+	     */
3685
+	    debug(81, 1) ("icapParseChunkSize: WARNING in mid-line, ret 0\n");
3686
+	    *chunk_size = 0;
3687
+	    return 0;
3688
+	}
3689
+	while (start < end) {
3690
+	    if (NULL == strchr(w_space, buf[start]))
3691
+		break;
3692
+	    start++;
3693
+	}
3694
+	while (start < end) {
3695
+	    if (NULL == strchr(w_space, buf[end - 1]))
3696
+		break;
3697
+	    end--;
3698
+	}
3699
+	/*
3700
+	 * if now end <= start we got an empty line. The previous
3701
+	 * chunk data should stop with a CRLF. In case that the
3702
+	 * other end does not follow the specs and sends no CRLF
3703
+	 * or too many empty lines, just continue till we have a
3704
+	 * non-empty line.
3705
+	 */
3706
+    } while (end <= start);
3707
+    debug(81, 3) ("icapParseChunkSize: start=%d, end=%d\n", start, end);
3708
+
3709
+    /* Non-empty line: Parse the chunk size */
3710
+    while (start < end) {
3711
+	c = buf[start++];
3712
+	if (c >= 'a' && c <= 'f') {
3713
+	    chunkSize = chunkSize * 16 + c - 'a' + 10;
3714
+	} else if (c >= 'A' && c <= 'F') {
3715
+	    chunkSize = chunkSize * 16 + c - 'A' + 10;
3716
+	} else if (c >= '0' && c <= '9') {
3717
+	    chunkSize = chunkSize * 16 + c - '0';
3718
+	} else {
3719
+	    if (!(c == ';' || c == ' ' || c == '\t')) {
3720
+		/*Syntax error: Chunksize expected. */
3721
+		*chunk_size = -2;	/* we are done */
3722
+		return nextStart;
3723
+	    }
3724
+	    /* Next comes a chunk extension */
3725
+	    break;
3726
+	}
3727
+    }
3728
+    /*
3729
+     * if we read a zero chunk, we reached the end. Mark this for
3730
+     * icapPconnTransferDone
3731
+     */
3732
+    *chunk_size = (chunkSize > 0) ? chunkSize : -2;
3733
+    debug(81, 3) ("icapParseChunkSize: return nextStart=%d\n", nextStart);
3734
+    return nextStart;
3735
+}
3736
+
3737
+/*
3738
+ * icapParseChunkedBody
3739
+ *
3740
+ * De-chunk an HTTP entity received from the ICAP server.
3741
+ * The 'store' function pointer is storeAppend() or memBufAppend().
3742
+ */
3743
+size_t
3744
+icapParseChunkedBody(IcapStateData * icap, STRCB * store, void *store_data)
3745
+{
3746
+    int bufOffset = 0;
3747
+    size_t bw = 0;
3748
+    MemBuf *cb = &icap->chunk_buf;
3749
+    const char *buf = cb->buf;
3750
+    int len = cb->size;
3751
+
3752
+    if (icap->chunk_size == -2) {
3753
+	debug(81, 3) ("zero end chunk reached\n");
3754
+	return 0;
3755
+    }
3756
+    debug(81, 3) ("%s:%d: chunk_size=%d\n", __FILE__, __LINE__,
3757
+	icap->chunk_size);
3758
+    if (icap->chunk_size < 0) {
3759
+	store(store_data, buf, len);
3760
+	cb->size = 0;
3761
+	return (size_t) len;
3762
+    }
3763
+    debug(81, 3) ("%s:%d: bufOffset=%d, len=%d\n", __FILE__, __LINE__,
3764
+	bufOffset, len);
3765
+    while (bufOffset < len) {
3766
+	debug(81, 3) ("%s:%d: bufOffset=%d, len=%d\n", __FILE__, __LINE__,
3767
+	    bufOffset, len);
3768
+	if (icap->chunk_size == 0) {
3769
+	    int x;
3770
+	    x = icapParseChunkSize(buf + bufOffset,
3771
+		len - bufOffset, &icap->chunk_size);
3772
+	    if (x < 1) {
3773
+		/* didn't find a valid chunk spec */
3774
+		break;
3775
+	    }
3776
+	    bufOffset += x;
3777
+	    debug(81, 3) ("got chunksize %d, new offset %d\n",
3778
+		icap->chunk_size, bufOffset);
3779
+	    if (icap->chunk_size == -2) {
3780
+		debug(81, 3) ("zero end chunk reached\n");
3781
+		break;
3782
+	    }
3783
+	}
3784
+	debug(81, 3) ("%s:%d: X\n", __FILE__, __LINE__);
3785
+	if (icap->chunk_size > 0) {
3786
+	    if (icap->chunk_size >= len - bufOffset) {
3787
+		store(store_data, buf + bufOffset, len - bufOffset);
3788
+		bw += (len - bufOffset);
3789
+		icap->chunk_size -= (len - bufOffset);
3790
+		bufOffset = len;
3791
+	    } else {
3792
+		store(store_data, buf + bufOffset, icap->chunk_size);
3793
+		bufOffset += icap->chunk_size;
3794
+		bw += icap->chunk_size;
3795
+		icap->chunk_size = 0;
3796
+	    }
3797
+	}
3798
+    }
3799
+    if (0 == bufOffset) {
3800
+	(void) 0;
3801
+    } else if (bufOffset == cb->size) {
3802
+	cb->size = 0;
3803
+    } else {
3804
+	assert(bufOffset <= cb->size);
3805
+	xmemmove(cb->buf, cb->buf + bufOffset, cb->size - bufOffset);
3806
+	cb->size -= bufOffset;
3807
+    }
3808
+    return bw;
3809
+}
3810
+
3811
+/*
3812
+ *  icapAddAuthUserHeader
3813
+ *
3814
+ *  Builds and adds the X-Authenticated-User header to an ICAP request headers.
3815
+ */
3816
+void
3817
+icapAddAuthUserHeader(MemBuf * mb, auth_user_request_t * auth_user_request)
3818
+{
3819
+    char *user = authenticateUserRequestUsername(auth_user_request);
3820
+    char *authuser;
3821
+    size_t len, userlen, schemelen, userofslen;
3822
+    char *userofs;
3823
+
3824
+    if (user == NULL) {
3825
+	debug(81, 5) ("icapAddAuthUserHeader: NULL username\n");
3826
+	return;
3827
+    }
3828
+    userlen = strlen(user);
3829
+    schemelen = strlen(Config.icapcfg.auth_scheme);
3830
+    len = userlen + schemelen + 1;
3831
+    authuser = xcalloc(len, 1);
3832
+
3833
+    if ((userofs = strstr(Config.icapcfg.auth_scheme, "%u")) == NULL) {
3834
+	/* simply add user at end of string */
3835
+	snprintf(authuser, len, "%s%s", Config.icapcfg.auth_scheme, user);
3836
+    } else {
3837
+	userofslen = userofs - Config.icapcfg.auth_scheme;
3838
+	xmemcpy(authuser, Config.icapcfg.auth_scheme, userofslen);
3839
+	xmemcpy(authuser + userofslen, user, userlen);
3840
+	xmemcpy(authuser + userofslen + userlen,
3841
+	    userofs + 2, schemelen - (userofslen + 2) + 1);
3842
+    }
3843
+
3844
+    memBufPrintf(mb, "X-Authenticated-User: %s\r\n", base64_encode(authuser));
3845
+    xfree(authuser);
3846
+}
3847
+
3848
+/*
3849
+ *  icapAddOriginIP
3850
+ *
3851
+ *  Builds and adds the X-Server-IP header to an ICAP request headers.
3852
+ */
3853
+void
3854
+icapAddOriginIP(MemBuf * mb, const char *host)
3855
+{
3856
+    const ipcache_addrs *addrs;
3857
+    struct in_addr s;
3858
+
3859
+    if (host == NULL) {
3860
+	debug(81, 5) ("icapAddOriginIP: NULL host\n");
3861
+	return;
3862
+    }
3863
+    addrs = ipcache_gethostbyname(host, IP_LOOKUP_IF_MISS);
3864
+    if (addrs == NULL) {
3865
+	/*
3866
+	 * http://www.i-cap.org/spec/draft-stecher-icap-subid-00.txt :
3867
+	 *
3868
+	 * [...] If the meta information for some header is not available,
3869
+	 * the header field MUST be omitted.
3870
+	 */
3871
+	debug(81, 5) ("icapAddOriginIP: can't tell IP address\n");
3872
+	return;
3873
+    }
3874
+    s = addrs->in_addrs[0];
3875
+    memBufPrintf(mb, "X-Server-IP: %s\r\n", inet_ntoa(s));
3876
+}
3877
Index: src/icap_opt.c
3878
===================================================================
3879
RCS file: src/icap_opt.c
3880
diff -N src/icap_opt.c
3881
--- /dev/null	1 Jan 1970 00:00:00 -0000
3882
+++ src/icap_opt.c	17 May 2006 17:58:01 -0000	1.1.16.1
3883
@@ -0,0 +1,523 @@
3884
+
3885
+/*
3886
+ * $Id$
3887
+ * 
3888
+ * DEBUG: section 81    Internet Content Adaptation Protocol (ICAP) Client OPTIONS
3889
+ * AUTHOR: Ralf Horstmann
3890
+ *
3891
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
3892
+ * ----------------------------------------------------------
3893
+ *
3894
+ *  Squid is the result of efforts by numerous individuals from
3895
+ *  the Internet community; see the CONTRIBUTORS file for full
3896
+ *  details.   Many organizations have provided support for Squid's
3897
+ *  development; see the SPONSORS file for full details.  Squid is
3898
+ *  Copyrighted (C) 2001 by the Regents of the University of
3899
+ *  California; see the COPYRIGHT file for full details.  Squid
3900
+ *  incorporates software developed and/or copyrighted by other
3901
+ *  sources; see the CREDITS file for full details.
3902
+ *
3903
+ *  This program is free software; you can redistribute it and/or modify
3904
+ *  it under the terms of the GNU General Public License as published by
3905
+ *  the Free Software Foundation; either version 2 of the License, or
3906
+ *  (at your option) any later version.
3907
+ *  
3908
+ *  This program is distributed in the hope that it will be useful,
3909
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
3910
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
3911
+ *  GNU General Public License for more details.
3912
+ *  
3913
+ *  You should have received a copy of the GNU General Public License
3914
+ *  along with this program; if not, write to the Free Software
3915
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
3916
+ *
3917
+ */
3918
+
3919
+#include "squid.h"
3920
+
3921
+/*************************************************************/
3922
+
3923
+/*
3924
+ * network related functions for OPTIONS request
3925
+ */
3926
+static void icapOptStart(void *data);
3927
+static void icapOptTimeout(int fd, void *data);
3928
+static void icapOptConnectDone(int server_fd, int status, void *data);
3929
+static void icapOptWriteComplete(int fd, char *bufnotused, size_t size, int errflag, void *data);
3930
+static void icapOptReadReply(int fd, void *data);
3931
+
3932
+/*
3933
+ * reply parsing functions
3934
+ */
3935
+static int icapOptParseReply(icap_service * s, IcapOptData * i);
3936
+static void icapOptParseEntry(icap_service * s, const char *blk_start, const char *blk_end);
3937
+static int icapIsolateLine(const char **parse_start, const char **blk_start, const char **blk_end);
3938
+
3939
+/*
3940
+ * helper functions
3941
+ */
3942
+static void icapOptDataInit(IcapOptData * i);
3943
+static void icapOptDataFree(IcapOptData * i);
3944
+
3945
+/*************************************************************/
3946
+
3947
+#define TIMEOUT 10
3948
+
3949
+void
3950
+icapOptInit()
3951
+{
3952
+    icap_service *s;
3953
+
3954
+    /* iterate over configured services */
3955
+    s = Config.icapcfg.service_head;
3956
+    while (s) {
3957
+	eventAdd("icapOptStart", icapOptStart, s, 5.0, 1);
3958
+	s = s->next;
3959
+    }
3960
+}
3961
+
3962
+void
3963
+icapOptShutdown()
3964
+{
3965
+    icap_service *s;
3966
+
3967
+    s = Config.icapcfg.service_head;
3968
+    while (s) {
3969
+	if (eventFind(icapOptStart, s)) {
3970
+	    eventDelete(icapOptStart, s);
3971
+	}
3972
+	s = s->next;
3973
+    }
3974
+}
3975
+
3976
+/*
3977
+ * mark a service as unreachable
3978
+ */
3979
+void
3980
+icapOptSetUnreachable(icap_service * s)
3981
+{
3982
+    s->unreachable = 1;
3983
+    debug(81, 5) ("icapOptSetUnreachable: got called for %s\n", s->uri);
3984
+    /*
3985
+     * if there is an options request scheduled, delete it and add
3986
+     * it again to reset the time to the default check_interval.
3987
+     */
3988
+    if (eventFind(icapOptStart, s)) {
3989
+	eventDelete(icapOptStart, s);
3990
+	eventAdd("icapOptStart", icapOptStart, s, Config.icapcfg.check_interval, 1);
3991
+    }
3992
+}
3993
+
3994
+static void
3995
+icapOptStart(void *data)
3996
+{
3997
+    icap_service *s = data;
3998
+    int fd;
3999
+    int ctimeout = TIMEOUT;
4000
+    const char *host = s->hostname;
4001
+    unsigned short port = s->port;
4002
+    debug(81, 3) ("icapOptStart: starting OPTIONS request for %s (%s)\n", s->name, s->uri);
4003
+    fd = comm_open(SOCK_STREAM,
4004
+	0,
4005
+	getOutgoingAddr(NULL),
4006
+	0,
4007
+	COMM_NONBLOCKING,
4008
+	"ICAP OPTIONS connection");
4009
+    if (fd < 0) {
4010
+	debug(81, 4) ("icapConnectStart: %s\n", xstrerror());
4011
+	eventAdd("icapOptStart", icapOptStart, s, Config.icapcfg.check_interval, 1);
4012
+	return;
4013
+    }
4014
+    assert(s->opt == NULL);	/* if not null, another options request might be running, which should not happen */
4015
+    s->opt = memAllocate(MEM_ICAP_OPT_DATA);
4016
+    icapOptDataInit(s->opt);
4017
+    cbdataLock(s);
4018
+    commSetTimeout(fd, ctimeout, icapOptTimeout, s);
4019
+    commConnectStart(fd, host, port, icapOptConnectDone, s);
4020
+}
4021
+
4022
+static void
4023
+icapOptTimeout(int fd, void *data)
4024
+{
4025
+    icap_service *s = data;
4026
+    IcapOptData *i = s->opt;
4027
+    int valid;
4028
+
4029
+    debug(81, 4) ("icapOptConnectTimeout: fd=%d, service=%s\n", fd, s->uri);
4030
+
4031
+    comm_close(fd);
4032
+    valid = cbdataValid(s);
4033
+    cbdataUnlock(s);
4034
+    if (!valid) {
4035
+	icapOptDataFree(i);
4036
+	s->opt = NULL;
4037
+	return;
4038
+    }
4039
+    /* try again later */
4040
+    icapOptDataFree(i);
4041
+    s->opt = NULL;
4042
+    s->unreachable = 1;
4043
+    debug(81, 3) ("icapOptConnectTimeout: unreachable=1, service=%s\n", s->uri);
4044
+    eventAdd("icapOptStart", icapOptStart, s, Config.icapcfg.check_interval, 1);
4045
+
4046
+}
4047
+
4048
+static void
4049
+icapOptConnectDone(int server_fd, int status, void *data)
4050
+{
4051
+    icap_service *s = data;
4052
+    IcapOptData *i = s->opt;
4053
+    MemBuf request;
4054
+    int valid;
4055
+
4056
+    valid = cbdataValid(s);
4057
+    cbdataUnlock(s);
4058
+    if (!valid) {
4059
+	comm_close(server_fd);
4060
+	icapOptDataFree(i);
4061
+	s->opt = NULL;
4062
+	return;
4063
+    }
4064
+    if (status != COMM_OK) {
4065
+	debug(81, 3) ("icapOptConnectDone: unreachable=1, service=%s\n", s->uri);
4066
+	comm_close(server_fd);
4067
+	icapOptDataFree(i);
4068
+	s->opt = NULL;
4069
+	s->unreachable = 1;
4070
+	eventAdd("icapOptStart", icapOptStart, s, Config.icapcfg.check_interval, 1);
4071
+	return;
4072
+    }
4073
+    debug(81, 3) ("icapOptConnectDone: Connection ok. Sending Options request for %s\n", s->name);
4074
+    memBufDefInit(&request);
4075
+    memBufPrintf(&request, "OPTIONS %s ICAP/1.0\r\n", s->uri);
4076
+    memBufPrintf(&request, "Host: %s\r\n", s->hostname);
4077
+    memBufPrintf(&request, "Connection: close\r\n");
4078
+    memBufPrintf(&request, "User-Agent: ICAP-Client-Squid/1.2\r\n");
4079
+    memBufPrintf(&request, "\r\n");
4080
+    cbdataLock(s);
4081
+    commSetTimeout(server_fd, TIMEOUT, icapOptTimeout, s);
4082
+    comm_write_mbuf(server_fd, request, icapOptWriteComplete, s);
4083
+}
4084
+
4085
+static void
4086
+icapOptWriteComplete(int fd, char *bufnotused, size_t size, int errflag, void *data)
4087
+{
4088
+    icap_service *s = data;
4089
+    IcapOptData *i = s->opt;
4090
+    int valid;
4091
+
4092
+    valid = cbdataValid(s);
4093
+    cbdataUnlock(s);
4094
+    if (!valid) {
4095
+	comm_close(fd);
4096
+	icapOptDataFree(i);
4097
+	s->opt = NULL;
4098
+	return;
4099
+    }
4100
+    debug(81, 5) ("icapOptWriteComplete: FD %d: size %d: errflag %d.\n",
4101
+	fd, size, errflag);
4102
+    if (size > 0) {
4103
+	fd_bytes(fd, size, FD_WRITE);
4104
+	kb_incr(&statCounter.icap.all.kbytes_out, size);
4105
+    }
4106
+    if (errflag) {
4107
+	/* cancel this for now */
4108
+	debug(81, 3) ("icapOptWriteComplete: unreachable=1, service=%s\n", s->uri);
4109
+	icapOptDataFree(i);
4110
+	s->opt = NULL;
4111
+	s->unreachable = 1;
4112
+	eventAdd("icapOptStart", icapOptStart, s, Config.icapcfg.check_interval, 1);
4113
+	comm_close(fd);
4114
+	return;
4115
+    }
4116
+    cbdataLock(s);
4117
+    commSetSelect(fd, COMM_SELECT_READ, icapOptReadReply, s, 0);
4118
+}
4119
+
4120
+static void
4121
+icapOptReadReply(int fd, void *data)
4122
+{
4123
+    icap_service *s = data;
4124
+    IcapOptData *i = s->opt;
4125
+    int size;
4126
+    int len = i->size - i->offset - 1;
4127
+    int valid;
4128
+
4129
+    valid = cbdataValid(s);
4130
+    cbdataUnlock(s);
4131
+    if (!valid) {
4132
+	comm_close(fd);
4133
+	icapOptDataFree(i);
4134
+	s->opt = NULL;
4135
+	return;
4136
+    }
4137
+    if (len == 0) {
4138
+	/* Grow the request memory area to accomodate for a large request */
4139
+	printf("PANIC: not enough memory\n");
4140
+#if 0
4141
+	i->buf = memReallocBuf(i->buf, i->size * 2, &i->size);
4142
+	debug(81, 2) ("icapoptReadReply: growing reply buffer: offset=%ld size=%ld\n",
4143
+	    (long) i->offset, (long) i->size);
4144
+	len = i->size - i->offset - 1;
4145
+#endif
4146
+    }
4147
+    size = FD_READ_METHOD(fd, i->buf + i->offset, len);
4148
+    i->offset += size;
4149
+    debug(81, 3) ("icapOptReadReply: Got %d bytes of data\n", size);
4150
+    if (size > 0) {
4151
+	/* do some statistics */
4152
+	fd_bytes(fd, size, FD_READ);
4153
+	kb_incr(&statCounter.icap.all.kbytes_in, size);
4154
+
4155
+	/* 
4156
+	 * some icap servers seem to ignore the  "Connection: close" header. so 
4157
+	 * after getting the complete option reply we close the connection 
4158
+	 * ourself.
4159
+	 */
4160
+	if ((i->headlen = headersEnd(i->buf, i->offset))) {
4161
+	    debug(81, 3) ("icapOptReadReply: EndOfResponse\n");
4162
+	    size = 0;
4163
+	}
4164
+    }
4165
+    if (size < 0) {
4166
+	debug(81, 3) ("icapOptReadReply: FD %d: read failure: %s.\n", fd, xstrerror());
4167
+	debug(81, 3) ("icapOptReadReply: unreachable=1, service=%s.\n", s->uri);
4168
+	s->unreachable = 1;
4169
+	icapOptDataFree(i);
4170
+	s->opt = NULL;
4171
+	eventAdd("icapOptStart", icapOptStart, s, Config.icapcfg.check_interval, 1);
4172
+	comm_close(fd);
4173
+    } else if (size == 0) {
4174
+	/* no more data, now we can parse the reply */
4175
+	debug(81, 3) ("icapOptReadReply: FD %d: connection closed\n", fd);
4176
+	i->buf[i->offset] = '\0';	/* for string functions */
4177
+	debug(81, 3) ("icapOptReadReply: unreachable=0, service=%s\n", s->uri);
4178
+
4179
+	if (!icapOptParseReply(s, i)) {
4180
+	    debug(81, 3) ("icapOptReadReply: OPTIONS request not successful. scheduling again in %d seconds\n", Config.icapcfg.check_interval);
4181
+	    s->unreachable = 1;
4182
+	} else
4183
+	    s->unreachable = 0;
4184
+
4185
+	if (s->options_ttl <= 0)
4186
+	    s->options_ttl = Config.icapcfg.check_interval;
4187
+	eventAdd("icapOptStart", icapOptStart, s, s->options_ttl, 1);
4188
+
4189
+	icapOptDataFree(i);
4190
+	s->opt = NULL;
4191
+	comm_close(fd);
4192
+    } else {
4193
+	/* data received */
4194
+	/* commSetSelect(fd, Type, handler, client_data, timeout) */
4195
+	cbdataLock(s);
4196
+	commSetSelect(fd, COMM_SELECT_READ, icapOptReadReply, data, 0);
4197
+    }
4198
+}
4199
+
4200
+static int
4201
+icapIsolateLine(const char **parse_start, const char **blk_start, const char **blk_end)
4202
+{
4203
+    int slen = strcspn(*parse_start, "\r\n");
4204
+
4205
+    if (!(*parse_start)[slen])	/* no crlf */
4206
+	return 0;
4207
+
4208
+    if (slen == 0)		/* empty line */
4209
+	return 0;
4210
+
4211
+    *blk_start = *parse_start;
4212
+    *blk_end = *blk_start + slen;
4213
+
4214
+    /* set it to the beginning of next line */
4215
+    *parse_start = *blk_end;
4216
+    while (**parse_start == '\r')	/* CR */
4217
+	(*parse_start)++;
4218
+    if (**parse_start == '\n')	/* LF */
4219
+	(*parse_start)++;
4220
+    return 1;
4221
+}
4222
+
4223
+/* process a single header entry between blk_start and blk_end */
4224
+static void
4225
+icapOptParseEntry(icap_service * s, const char *blk_start, const char *blk_end)
4226
+{
4227
+    const char *name_end = strchr(blk_start, ':');
4228
+    const int name_len = name_end ? name_end - blk_start : 0;
4229
+    const char *value_start = blk_start + name_len + 1;		/* skip ':' */
4230
+    int value_len;
4231
+    int new;
4232
+
4233
+    if (!name_len || name_end > blk_end) {
4234
+	debug(81, 5) ("icapOptParseEntry: strange header. skipping\n");
4235
+	return;
4236
+    }
4237
+    if (name_len > 65536) {
4238
+	debug(81, 5) ("icapOptParseEntry: unusual long header item. skipping.\n");
4239
+	return;
4240
+    }
4241
+    while (xisspace(*value_start) && value_start < blk_end) {
4242
+	value_start++;
4243
+    }
4244
+    if (value_start >= blk_end) {
4245
+	debug(81, 5) ("icapOptParseEntry: no value found\n");
4246
+	return;
4247
+    }
4248
+    value_len = blk_end - value_start;
4249
+
4250
+
4251
+    /* extract information */
4252
+    if (!strncasecmp("Allow", blk_start, name_len)) {
4253
+	debug(81, 5) ("icapOptParseEntry: found Allow\n");
4254
+	if (!strncmp("204", value_start, 3)) {
4255
+	    s->flags.allow_204 = 1;
4256
+	} else {
4257
+	    debug(81, 3) ("icapOptParseEntry: Allow value unknown");
4258
+	}
4259
+    } else if (!strncasecmp("Connection", blk_start, name_len)) {
4260
+	debug(81, 5) ("icapOptParseEntry: found Connection\n");
4261
+    } else if (!strncasecmp("Encapsulated", blk_start, name_len)) {
4262
+	debug(81, 5) ("icapOptParseEntry: found Encapsulated\n");
4263
+    } else if (!strncasecmp("ISTAG", blk_start, name_len)) {
4264
+	debug(81, 5) ("icapOptParseEntry: found ISTAG\n");
4265
+	stringClean(&s->istag);
4266
+	stringLimitInit(&s->istag, value_start, value_len);
4267
+    } else if (!strncasecmp("Max-Connections", blk_start, name_len)) {
4268
+	debug(81, 5) ("icapOptParseEntry: found Max-Connections\n");
4269
+	errno = 0;
4270
+	new = strtol(value_start, NULL, 10);
4271
+	if (errno) {
4272
+	    debug(81, 5) ("icapOptParseEntry: Max-Connections: could not parse value\n");
4273
+	} else {
4274
+	    debug(81, 5) ("icapOptParseEntry: Max-Connections: new value=%d\n", new);
4275
+	    s->max_connections = new;
4276
+	}
4277
+    } else if (!strncasecmp("Methods", blk_start, name_len)) {
4278
+	debug(81, 5) ("icapOptParseEntry: found Methods\n");
4279
+    } else if (!strncasecmp("Options-TTL", blk_start, name_len)) {
4280
+	debug(81, 5) ("icapOptParseEntry: found Options-TTL\n");
4281
+	errno = 0;
4282
+	new = strtol(value_start, NULL, 10);
4283
+	if (errno) {
4284
+	    debug(81, 5) ("icapOptParseEntry: Options-TTL: could not parse value\n");
4285
+	} else {
4286
+	    debug(81, 5) ("icapOptParseEntry: Options-TTL: new value=%d\n", new);
4287
+	    s->options_ttl = new;
4288
+	}
4289
+    } else if (!strncasecmp("Preview", blk_start, name_len)) {
4290
+	debug(81, 5) ("icapOptParseEntry: found Preview\n");
4291
+	errno = 0;
4292
+	new = strtol(value_start, NULL, 10);
4293
+	if (errno) {
4294
+	    debug(81, 5) ("icapOptParseEntry: Preview: could not parse value\n");
4295
+	} else {
4296
+	    debug(81, 5) ("icapOptParseEntry: Preview: new value=%d\n", new);
4297
+	    s->preview = new;
4298
+	}
4299
+    } else if (!strncasecmp("Service", blk_start, name_len)) {
4300
+	debug(81, 5) ("icapOptParseEntry: found Service\n");
4301
+    } else if (!strncasecmp("Service-ID", blk_start, name_len)) {
4302
+	debug(81, 5) ("icapOptParseEntry: found Service-ID\n");
4303
+    } else if (!strncasecmp("Transfer-Preview", blk_start, name_len)) {
4304
+	debug(81, 5) ("icapOptParseEntry: found Transfer-Preview\n");
4305
+	stringClean(&s->transfer_preview);
4306
+	stringLimitInit(&s->transfer_preview, value_start, value_len);
4307
+    } else if (!strncasecmp("Transfer-Ignore", blk_start, name_len)) {
4308
+	debug(81, 5) ("icapOptParseEntry: found Transfer-Ignore\n");
4309
+	stringClean(&s->transfer_ignore);
4310
+	stringLimitInit(&s->transfer_ignore, value_start, value_len);
4311
+    } else if (!strncasecmp("Transfer-Complete", blk_start, name_len)) {
4312
+	debug(81, 5) ("icapOptParseEntry: found Transfer-Complete\n");
4313
+	stringClean(&s->transfer_complete);
4314
+	stringLimitInit(&s->transfer_complete, value_start, value_len);
4315
+    } else if (!strncasecmp("X-Include", blk_start, name_len)) {
4316
+	debug(81, 5) ("icapOptParseEntry: found X-Include\n");
4317
+	if (strstr(value_start, "X-Client-IP")) {
4318
+	    debug(81, 5) ("icapOptParseEntry: X-Include: found X-Client-IP\n");
4319
+	    s->flags.need_x_client_ip = 1;
4320
+	}
4321
+	if (strstr(value_start, "X-Server-IP")) {
4322
+	    debug(81, 5) ("icapOptParseEntry: X-Include: found X-Server-IP\n");
4323
+	    s->flags.need_x_server_ip = 1;
4324
+	}
4325
+	if (strstr(value_start, "X-Authenticated-User")) {
4326
+	    debug(81, 5) ("icapOptParseEntry: X-Include: found X-Authenticated-User\n");
4327
+	    s->flags.need_x_authenticated_user = 1;
4328
+	}
4329
+    } else {
4330
+	debug(81, 5) ("icapOptParseEntry: unknown options header\n");
4331
+    }
4332
+}
4333
+
4334
+/* parse OPTIONS reply */
4335
+static int
4336
+icapOptParseReply(icap_service * s, IcapOptData * i)
4337
+{
4338
+    int version_major, version_minor;
4339
+    const char *str_status;
4340
+    int status;
4341
+    const char *buf = i->buf;
4342
+    const char *parse_start;
4343
+    const char *head_end;
4344
+    const char *blk_start;
4345
+    const char *blk_end;
4346
+
4347
+    if ((status =
4348
+	    icapParseStatusLine(i->buf, i->offset,
4349
+		&version_major, &version_minor, &str_status)) < 0) {
4350
+	debug(81, 2) ("icapOptParseReply: bad status line <%s>\n", i->buf);
4351
+	return 0;
4352
+    }
4353
+    debug(81, 3) ("icapOptParseReply: got reply: <ICAP/%d.%d %d %s>\n", version_major, version_minor, status, str_status);
4354
+
4355
+    if (status != 200) {
4356
+	debug(81, 3) ("icapOptParseReply: status = %d != 200\n", status);
4357
+	return 0;
4358
+    }
4359
+    parse_start = buf;
4360
+    if (i->headlen == 0)
4361
+	i->headlen = headersEnd(parse_start, s->opt->offset);
4362
+
4363
+    if (!i->headlen) {
4364
+	debug(81, 2) ("icapOptParseReply: end of headers could not be found\n");
4365
+	return 0;
4366
+    }
4367
+    head_end = parse_start + i->headlen - 1;
4368
+    while (*(head_end - 1) == '\r')
4369
+	head_end--;
4370
+    assert(*(head_end - 1) == '\n');
4371
+    if (*head_end != '\r' && *head_end != '\n')
4372
+	return 0;		/* failure */
4373
+
4374
+    /* skip status line */
4375
+    if (!icapIsolateLine(&parse_start, &blk_start, &blk_end)) {
4376
+	debug(81, 3) ("icapOptParseReply: failure in isolating status line\n");
4377
+	return 0;
4378
+
4379
+    }
4380
+    /* now we might start real parsing */
4381
+    while (icapIsolateLine(&parse_start, &blk_start, &blk_end)) {
4382
+	if (blk_end > head_end || blk_start > head_end || blk_start >= blk_end) {
4383
+	    debug(81, 3) ("icapOptParseReply: header limit exceeded. finished.\n");
4384
+	    break;
4385
+	}
4386
+	icapOptParseEntry(s, blk_start, blk_end);
4387
+    }
4388
+    return 1;
4389
+}
4390
+
4391
+static void
4392
+icapOptDataInit(IcapOptData * i)
4393
+{
4394
+    i->buf = memAllocBuf(HTTP_REPLY_BUF_SZ, &i->size);
4395
+    i->offset = 0;
4396
+    i->headlen = 0;
4397
+}
4398
+
4399
+static void
4400
+icapOptDataFree(IcapOptData * i)
4401
+{
4402
+    if (i) {
4403
+	memFreeBuf(i->size, i->buf);
4404
+	memFree(i, MEM_ICAP_OPT_DATA);
4405
+    }
4406
+}
4407
Index: src/icap_reqmod.c
4408
===================================================================
4409
RCS file: src/icap_reqmod.c
4410
diff -N src/icap_reqmod.c
4411
--- /dev/null	1 Jan 1970 00:00:00 -0000
4412
+++ src/icap_reqmod.c	31 Jan 2007 18:11:13 -0000	1.1.14.10
4413
@@ -0,0 +1,989 @@
4414
+
4415
+/*
4416
+ * $Id$
4417
+ *
4418
+ * DEBUG: section 81    Internet Content Adaptation Protocol (ICAP) Client
4419
+ * AUTHOR: Geetha Manjunath, Hewlett Packard Company
4420
+ *
4421
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
4422
+ * ----------------------------------------------------------
4423
+ *
4424
+ *  Squid is the result of efforts by numerous individuals from
4425
+ *  the Internet community; see the CONTRIBUTORS file for full
4426
+ *  details.   Many organizations have provided support for Squid's
4427
+ *  development; see the SPONSORS file for full details.  Squid is
4428
+ *  Copyrighted (C) 2001 by the Regents of the University of
4429
+ *  California; see the COPYRIGHT file for full details.  Squid
4430
+ *  incorporates software developed and/or copyrighted by other
4431
+ *  sources; see the CREDITS file for full details.
4432
+ *
4433
+ *  This program is free software; you can redistribute it and/or modify
4434
+ *  it under the terms of the GNU General Public License as published by
4435
+ *  the Free Software Foundation; either version 2 of the License, or
4436
+ *  (at your option) any later version.
4437
+ *  
4438
+ *  This program is distributed in the hope that it will be useful,
4439
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
4440
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
4441
+ *  GNU General Public License for more details.
4442
+ *  
4443
+ *  You should have received a copy of the GNU General Public License
4444
+ *  along with this program; if not, write to the Free Software
4445
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
4446
+ *
4447
+ */
4448
+
4449
+#include "squid.h"
4450
+
4451
+#define ICAP_PROXY_KEEP_ALIVE 0
4452
+
4453
+/*
4454
+ * These once-static functions are required to be global for ICAP
4455
+ */
4456
+
4457
+PF clientReadRequest;
4458
+PF connStateFree;
4459
+StoreEntry *clientCreateStoreEntry(clientHttpRequest *, method_t, request_flags);
4460
+int clientReadDefer(int fd, void *data);
4461
+int clientCheckContentLength(request_t * r);
4462
+void clientProcessRequest(clientHttpRequest *);
4463
+int clientCachable(clientHttpRequest *);
4464
+int clientHierarchical(clientHttpRequest *);
4465
+void clientReadBody(request_t * request, char *buf, size_t size,
4466
+    CBCB * callback, void *cbdata);
4467
+static void icapReqModPassHttpBody(IcapStateData * icap, char *buf, size_t size,
4468
+    CBCB * callback, void *cbdata);
4469
+
4470
+static PF icapReqModReadHttpHdrs;
4471
+static PF icapReqModReadHttpBody;
4472
+static CWCB icapReqModSendBodyChunk;
4473
+static CBCB icapReqModBodyHandler;
4474
+static BODY_HANDLER icapReqModBodyReader;
4475
+static STRCB icapReqModMemBufAppend;
4476
+
4477
+#define EXPECTED_ICAP_HEADER_LEN 256
4478
+static const char *crlf = "\r\n";
4479
+
4480
+/*
4481
+ * icapExpectedHttpReqHdrSize
4482
+ *
4483
+ * calculate the size of the HTTP headers that we expect
4484
+ * to read from the ICAP server.
4485
+ */
4486
+static int
4487
+icapExpectedHttpReqHdrSize(IcapStateData * icap)
4488
+{
4489
+    if (icap->enc.req_body > -1 && icap->enc.req_hdr > -1)
4490
+	return (icap->enc.req_body - icap->enc.req_hdr);
4491
+    if (icap->enc.null_body > -1)
4492
+	return icap->enc.null_body;
4493
+    fatal("icapExpectedHttpReqHdrSize: unexpected case");
4494
+    return 0;
4495
+}
4496
+
4497
+/*
4498
+ * icapReqModCreateClientState
4499
+ *
4500
+ * Creates fake client_side data structures so we can use
4501
+ * that module to read/parse the HTTP request that we read
4502
+ * from the ICAP server.
4503
+ */
4504
+static clientHttpRequest *
4505
+icapReqModCreateClientState(IcapStateData * icap, request_t * request)
4506
+{
4507
+    clientHttpRequest *http;
4508
+    if (!cbdataValid(icap->reqmod.client_cookie)) {
4509
+	debug(81, 3) ("Whups, client cookie invalid\n");
4510
+	icap->reqmod.client_fd = -1;
4511
+	return NULL;
4512
+    }
4513
+    http = cbdataAlloc(clientHttpRequest);
4514
+    /*
4515
+     * use our own urlCanonicalClean here, because urlCanonicalClean
4516
+     * may strip everything after a question-mark. As http->uri
4517
+     * is used when doing a request to a parent proxy, we need the full
4518
+     * url here.
4519
+     */
4520
+    http->uri = xstrdup(urlCanonical(icap->request));
4521
+    http->range_iter.boundary = StringNull;
4522
+    http->request = requestLink(request ? request : icap->request);
4523
+    http->flags.did_icap_reqmod = 1;
4524
+    http->start = icap->reqmod.start;
4525
+    if (request)
4526
+	http->http_ver = request->http_ver;
4527
+#if ICAP_PROXY_KEEP_ALIVE
4528
+    /*
4529
+     * Here it is possible becouse we are using as client_cookie the original http->conn
4530
+     * if we will keep this code we must declare an icap->conn field........
4531
+     * Will work if pipeline_prefetch is not enabled
4532
+     * We are using a dummy ConnStateData structure, just to free
4533
+     * old clientHttpRequest :-( 
4534
+     * OK,all this code is a hack and possibly must not exists in cvs ......
4535
+     */
4536
+
4537
+    http->conn = icap->reqmod.client_cookie;
4538
+    assert(http->conn->chr->next == NULL);
4539
+    {
4540
+	ConnStateData *dummyconn;
4541
+	clientHttpRequest *H;
4542
+	dummyconn = cbdataAlloc(ConnStateData);
4543
+	dummyconn->fd = icap->reqmod.client_fd;
4544
+	dummyconn->pinning.fd = -1;
4545
+	H = DLINK_HEAD(conn->reqs);
4546
+	dlinkAddTail(H, &H->node, &dummyconn->reqs);
4547
+	H->conn = dummyconn;
4548
+	comm_add_close_handler(dummyconn->fd, connStateFree, dummyconn);
4549
+    }
4550
+    http->conn->chr = http;
4551
+#else
4552
+    http->conn = cbdataAlloc(ConnStateData);
4553
+    http->conn->fd = icap->reqmod.client_fd;
4554
+    http->conn->pinning.fd = -1;
4555
+    http->conn->in.size = 0;
4556
+    http->conn->in.buf = NULL;
4557
+    http->conn->log_addr = icap->reqmod.log_addr;
4558
+    dlinkAddTail(http, &http->node, &http->conn->reqs);
4559
+    comm_add_close_handler(http->conn->fd, connStateFree, http->conn);
4560
+#endif
4561
+    http->icap_reqmod = NULL;
4562
+    return http;
4563
+}
4564
+
4565
+/*
4566
+ * icapReqModInterpretHttpRequest
4567
+ *
4568
+ * Interpret an HTTP request that we read from the ICAP server.
4569
+ * Create some "fake" clientHttpRequest and ConnStateData structures
4570
+ * so we can pass this new request off to the routines in
4571
+ * client_side.c.
4572
+ */
4573
+static void
4574
+icapReqModInterpretHttpRequest(IcapStateData * icap, request_t * request)
4575
+{
4576
+    clientHttpRequest *http = icapReqModCreateClientState(icap, request);
4577
+    if (NULL == http)
4578
+	return;
4579
+    /*
4580
+     * bits from clientReadRequest
4581
+     */
4582
+    request->content_length = httpHeaderGetSize(&request->header,
4583
+	HDR_CONTENT_LENGTH);
4584
+    if (!urlCheckRequest(request) ||
4585
+	httpHeaderHas(&request->header, HDR_TRANSFER_ENCODING)) {
4586
+	ErrorState *err;
4587
+	err = errorCon(ERR_UNSUP_REQ, HTTP_NOT_IMPLEMENTED, request);
4588
+	request->flags.proxy_keepalive = 0;
4589
+	http->entry =
4590
+	    clientCreateStoreEntry(http, request->method, null_request_flags);
4591
+	errorAppendEntry(http->entry, err);
4592
+	return;
4593
+    }
4594
+    if (!clientCheckContentLength(request)) {
4595
+	ErrorState *err;
4596
+	err = errorCon(ERR_INVALID_REQ, HTTP_LENGTH_REQUIRED, request);
4597
+	http->entry =
4598
+	    clientCreateStoreEntry(http, request->method, null_request_flags);
4599
+	errorAppendEntry(http->entry, err);
4600
+	return;
4601
+    }
4602
+    /* Do we expect a request-body? */
4603
+    if (request->content_length > 0) {
4604
+	debug(81, 5) ("handing request bodies in ICAP REQMOD\n");
4605
+	if (request->body_reader_data)
4606
+	    cbdataUnlock(request->body_reader_data);
4607
+	request->body_reader = icapReqModBodyReader;
4608
+	request->body_reader_data = icap;	/* XXX cbdataLock? */
4609
+	cbdataLock(icap);	/*Yes sure ..... */
4610
+	memBufDefInit(&icap->reqmod.http_entity.buf);
4611
+    }
4612
+    if (clientCachable(http))
4613
+	request->flags.cachable = 1;
4614
+    if (clientHierarchical(http))
4615
+	request->flags.hierarchical = 1;
4616
+    clientProcessRequest(http);
4617
+}
4618
+
4619
+/*
4620
+ * icapReqModParseHttpError
4621
+ *
4622
+ * Handle an error when parsing the new HTTP request we read
4623
+ * from the ICAP server.
4624
+ */
4625
+static void
4626
+icapReqModParseHttpError(IcapStateData * icap, const char *reason)
4627
+{
4628
+    debug(81, 1) ("icapReqModParseHttpError: %s\n", reason);
4629
+}
4630
+
4631
+/*
4632
+ * icapEntryError
4633
+ *
4634
+ * A wrapper for errorCon() and errorAppendEntry().
4635
+ */
4636
+static void
4637
+icapEntryError(IcapStateData * icap, err_type et, http_status hs, int xerrno)
4638
+{
4639
+    ErrorState *err;
4640
+    clientHttpRequest *http = icapReqModCreateClientState(icap, NULL);
4641
+    if (NULL == http)
4642
+	return;
4643
+    http->entry = clientCreateStoreEntry(http,
4644
+	icap->request->method, null_request_flags);
4645
+    err = errorCon(et, hs, icap->request);
4646
+    err->xerrno = xerrno;
4647
+    errorAppendEntry(http->entry, err);
4648
+}
4649
+
4650
+/*
4651
+ * icapReqModParseHttpRequest
4652
+ * 
4653
+ * Parse the HTTP request that we read from the ICAP server.
4654
+ * Creates and fills in the request_t structure.
4655
+ */
4656
+static void
4657
+icapReqModParseHttpRequest(IcapStateData * icap)
4658
+{
4659
+    char *mstr;
4660
+    char *uri;
4661
+    char *inbuf;
4662
+    char *t;
4663
+    char *token;
4664
+    char *headers;
4665
+    method_t method;
4666
+    request_t *request;
4667
+    http_version_t http_ver;
4668
+    int reqlen = icap->reqmod.hdr_buf.size;
4669
+    int hdrlen;
4670
+
4671
+    /*
4672
+     * Lazy, make a copy of the buf so I can chop it up with strtok()
4673
+     */
4674
+    inbuf = xcalloc(reqlen + 1, 1);
4675
+    memcpy(inbuf, icap->reqmod.hdr_buf.buf, reqlen);
4676
+
4677
+    if ((mstr = strtok(inbuf, "\t ")) == NULL) {
4678
+	debug(81, 1) ("icapReqModParseHttpRequest: Can't get request method\n");
4679
+	icapReqModParseHttpError(icap, "error:invalid-request-method");
4680
+	xfree(inbuf);
4681
+	return;
4682
+    }
4683
+    method = urlParseMethod(mstr);
4684
+    if (method == METHOD_NONE) {
4685
+	debug(81, 1) ("icapReqModParseHttpRequest: Unsupported method '%s' (%d)\n",
4686
+	    mstr, strlen(mstr));
4687
+	icapReqModParseHttpError(icap, "error:unsupported-request-method");
4688
+	xfree(inbuf);
4689
+	return;
4690
+    }
4691
+    /* look for URL+HTTP/x.x */
4692
+    if ((uri = strtok(NULL, "\n")) == NULL) {
4693
+	debug(81, 1) ("icapReqModParseHttpRequest: Missing URI\n");
4694
+	icapReqModParseHttpError(icap, "error:missing-url");
4695
+	xfree(inbuf);
4696
+	return;
4697
+    }
4698
+    while (xisspace(*uri))
4699
+	uri++;
4700
+    t = uri + strlen(uri);
4701
+    assert(*t == '\0');
4702
+    token = NULL;
4703
+    while (t > uri) {
4704
+	t--;
4705
+	if (xisspace(*t) && !strncmp(t + 1, "HTTP/", 5)) {
4706
+	    token = t + 1;
4707
+	    break;
4708
+	}
4709
+    }
4710
+    while (t > uri && xisspace(*t))
4711
+	*(t--) = '\0';
4712
+    debug(81, 5) ("icapReqModParseHttpRequest: URI is '%s'\n", uri);
4713
+    if (token == NULL) {
4714
+	debug(81, 3) ("icapReqModParseHttpRequest: Missing HTTP identifier\n");
4715
+	icapReqModParseHttpError(icap, "error:missing-http-ident");
4716
+	xfree(inbuf);
4717
+	return;
4718
+    }
4719
+    if (sscanf(token + 5, "%d.%d", &http_ver.major, &http_ver.minor) != 2) {
4720
+	debug(81, 3) ("icapReqModParseHttpRequest: Invalid HTTP identifier.\n");
4721
+	icapReqModParseHttpError(icap, "error:invalid-http-ident");
4722
+	xfree(inbuf);
4723
+	return;
4724
+    }
4725
+    debug(81, 6) ("icapReqModParseHttpRequest: Client HTTP version %d.%d.\n",
4726
+	http_ver.major, http_ver.minor);
4727
+
4728
+    headers = strtok(NULL, null_string);
4729
+    hdrlen = inbuf + reqlen - headers;
4730
+
4731
+    if ((request = urlParse(method, uri)) == NULL) {
4732
+	debug(81, 3) ("Invalid URL: %s at %s:%d\n", uri, __FILE__, __LINE__);
4733
+	icapEntryError(icap, ERR_INVALID_URL, HTTP_BAD_REQUEST, 0);
4734
+	xfree(inbuf);
4735
+	return;
4736
+    }
4737
+    /* compile headers */
4738
+    if (!httpHeaderParse(&request->header, headers, headers + hdrlen)) {
4739
+	debug(81, 3) ("Failed to parse HTTP headers for: %s at %s:%d",
4740
+	    uri, __FILE__, __LINE__);
4741
+	icapEntryError(icap, ERR_INVALID_REQ, HTTP_BAD_REQUEST, 0);
4742
+	xfree(inbuf);
4743
+	return;
4744
+    }
4745
+    debug(81,
4746
+	3)
4747
+	("icapReqModParseHttpRequest: successfully parsed the HTTP request\n");
4748
+    request->http_ver = http_ver;
4749
+    request->client_addr = icap->request->client_addr;
4750
+    request->client_port = icap->request->client_port;
4751
+    request->my_addr = icap->request->my_addr;
4752
+    request->my_port = icap->request->my_port;
4753
+    request->class = icap->request->class;
4754
+    if (icap->request->auth_user_request) {
4755
+	/* Copy authentification info in new request */
4756
+	request->auth_user_request = icap->request->auth_user_request;
4757
+	authenticateAuthUserRequestLock(request->auth_user_request);
4758
+    }
4759
+    request->content_length = httpHeaderGetSize(&request->header,
4760
+	HDR_CONTENT_LENGTH);
4761
+    if (strBuf(icap->request->extacl_log))
4762
+	request->extacl_log = stringDup(&icap->request->extacl_log);
4763
+    if (icap->request->extacl_user)
4764
+	request->extacl_user = xstrdup(icap->request->extacl_user);
4765
+    if (icap->request->extacl_passwd)
4766
+	request->extacl_passwd = xstrdup(icap->request->extacl_passwd);
4767
+#if ICAP_PROXY_KEEP_ALIVE
4768
+    /*
4769
+     * Copy the proxy_keepalive flag from the original request
4770
+     */
4771
+    request->flags.proxy_keepalive = icap->request->flags.proxy_keepalive;
4772
+    /*
4773
+     * If proxy_keepalive was set for the original request, make
4774
+     * sure that the adapated request also has the necessary headers
4775
+     * for keepalive
4776
+     */
4777
+    if (request->flags.proxy_keepalive) {
4778
+	if (!httpMsgIsPersistent(http_ver, &request->header))
4779
+	    request->flags.proxy_keepalive = 0;
4780
+    }
4781
+#endif
4782
+    icapReqModInterpretHttpRequest(icap, request);
4783
+    xfree(inbuf);
4784
+}
4785
+
4786
+/*
4787
+ * icapReqModHandoffRespMod
4788
+ *
4789
+ * Handles the case where a REQMOD request results in an HTTP REPLY
4790
+ * (instead of an ICAP REPLY that contains a new HTTP REQUEST).  We
4791
+ * prepare the IcapStateData for passing off to the icap_reqmod
4792
+ * code, where we have functions for reading HTTP replies in ICAP
4793
+ * messages.
4794
+ */
4795
+static void
4796
+icapReqModHandoffRespMod(IcapStateData * icap)
4797
+{
4798
+    extern PF icapReadReply;
4799
+    clientHttpRequest *http = icapReqModCreateClientState(icap, NULL);
4800
+    if (NULL == http)
4801
+	return;
4802
+    assert(icap->request);
4803
+    http->entry = clientCreateStoreEntry(http,
4804
+	icap->request->method, icap->request->flags);
4805
+    icap->respmod.entry = http->entry;
4806
+    storeLockObject(icap->respmod.entry);
4807
+
4808
+    /* icap->http_flags = ? */
4809
+    memBufDefInit(&icap->respmod.buffer);
4810
+    memBufDefInit(&icap->chunk_buf);
4811
+    assert(icap->current_service);
4812
+    icapReadReply(icap->icap_fd, icap);
4813
+}
4814
+
4815
+/*
4816
+ * icapReqModKeepAliveOrClose
4817
+ *
4818
+ * Called when we are done reading from the ICAP server.
4819
+ * Either close the connection or keep it open for a future
4820
+ * transaction.
4821
+ */
4822
+static void
4823
+icapReqModKeepAliveOrClose(IcapStateData * icap)
4824
+{
4825
+    int fd = icap->icap_fd;
4826
+    debug(81, 3) ("%s:%d FD %d\n", __FILE__, __LINE__, fd);
4827
+    if (fd < 0)
4828
+	return;
4829
+    if (!icap->flags.keep_alive) {
4830
+	debug(81, 3) ("%s:%d keep_alive not set, closing\n", __FILE__,
4831
+	    __LINE__);
4832
+	comm_close(fd);
4833
+	return;
4834
+    }
4835
+    if (icap->request->content_length < 0) {
4836
+	/* no message body */
4837
+	debug(81, 3) ("%s:%d no message body\n", __FILE__, __LINE__);
4838
+	if (1 != icap->reqmod.hdr_state) {
4839
+	    /* didn't get to end of HTTP headers */
4840
+	    debug(81, 3) ("%s:%d didnt find end of headers, closing\n",
4841
+		__FILE__, __LINE__);
4842
+	    comm_close(fd);
4843
+	    return;
4844
+	}
4845
+    } else if (icap->reqmod.http_entity.bytes_read !=
4846
+	icap->request->content_length) {
4847
+	debug(81, 3) ("%s:%d bytes_read (%" PRINTF_OFF_T ") != content_length (%" PRINTF_OFF_T ")\n",
4848
+	    __FILE__, __LINE__, icap->reqmod.http_entity.bytes_read,
4849
+	    icap->request->content_length);
4850
+	/* an error */
4851
+	comm_close(fd);
4852
+	return;
4853
+    }
4854
+    debug(81, 3) ("%s:%d looks good, keeping alive\n", __FILE__, __LINE__);
4855
+    commSetDefer(fd, NULL, NULL);
4856
+    commSetTimeout(fd, -1, NULL, NULL);
4857
+    commSetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0);
4858
+    comm_remove_close_handler(fd, icapStateFree, icap);
4859
+    pconnPush(fd, icap->current_service->hostname, icap->current_service->port, NULL, NULL, 0);
4860
+    icap->icap_fd = -1;
4861
+    icapStateFree(-1, icap);
4862
+}
4863
+
4864
+/*
4865
+ * icapReqModReadHttpHdrs
4866
+ *
4867
+ * Read the HTTP reply from the ICAP server.  Uses the values
4868
+ * from the ICAP Encapsulation header to know how many bytes
4869
+ * to read.
4870
+ */
4871
+static void
4872
+icapReqModReadHttpHdrs(int fd, void *data)
4873
+{
4874
+    IcapStateData *icap = data;
4875
+    LOCAL_ARRAY(char, tmpbuf, SQUID_TCP_SO_RCVBUF);
4876
+    int rl;
4877
+    debug(81, 3) ("icapReqModReadHttpHdrs:\n");
4878
+    assert(fd == icap->icap_fd);
4879
+    assert(icap->enc.req_hdr == 0);
4880
+    if (0 == icap->reqmod.hdr_state) {
4881
+	int expect = icapExpectedHttpReqHdrSize(icap);
4882
+	int so_far = icap->http_header_bytes_read_so_far;
4883
+	int needed = expect - so_far;
4884
+	debug(81, 3) ("expect=%d\n", expect);
4885
+	debug(81, 3) ("so_far=%d\n", so_far);
4886
+	debug(81, 3) ("needed=%d\n", needed);
4887
+	assert(needed >= 0);
4888
+	if (0 == expect) {
4889
+	    fatalf("unexpected condition in %s:%d", __FILE__, __LINE__);
4890
+	}
4891
+	rl = FD_READ_METHOD(fd, tmpbuf, needed);
4892
+	debug(81, 3) ("icapReqModReadHttpHdrs: read %d bytes\n", rl);
4893
+	if (rl < 0) {
4894
+	    fatalf("need to handle read error at %s:%d", __FILE__, __LINE__);
4895
+	}
4896
+	fd_bytes(fd, rl, FD_READ);
4897
+	kb_incr(&statCounter.icap.all.kbytes_in, rl);
4898
+	memBufAppend(&icap->reqmod.hdr_buf, tmpbuf, rl);
4899
+	icap->http_header_bytes_read_so_far += rl;
4900
+	if (rl != needed) {
4901
+	    /* still more header data to read */
4902
+	    commSetSelect(fd, COMM_SELECT_READ, icapReqModReadHttpHdrs, icap,
4903
+		0);
4904
+	    return;
4905
+	}
4906
+	icap->reqmod.hdr_state = 1;
4907
+    }
4908
+    assert(1 == icap->reqmod.hdr_state);
4909
+    debug(81, 3) ("icapReqModReadHttpHdrs: read the entire request headers\n");
4910
+    icapReqModParseHttpRequest(icap);
4911
+    if (-1 == icap->reqmod.client_fd) {
4912
+	/* we detected that the original client_side went away */
4913
+	icapReqModKeepAliveOrClose(icap);
4914
+    } else if (icap->enc.req_body > -1) {
4915
+	icap->chunk_size = 0;
4916
+	memBufDefInit(&icap->chunk_buf);
4917
+	commSetSelect(fd, COMM_SELECT_READ, icapReqModReadHttpBody, icap, 0);
4918
+    } else {
4919
+	icapReqModKeepAliveOrClose(icap);
4920
+    }
4921
+}
4922
+
4923
+
4924
+/*
4925
+ * icapReqModReadIcapPart
4926
+ *
4927
+ * Read the ICAP reply header.
4928
+ */
4929
+static void
4930
+icapReqModReadIcapPart(int fd, void *data)
4931
+{
4932
+    IcapStateData *icap = data;
4933
+    int version_major, version_minor;
4934
+    const char *str_status;
4935
+    int x;
4936
+    const char *start;
4937
+    const char *end;
4938
+    int status;
4939
+    int isIcap = 0;
4940
+    int directResponse = 0;
4941
+
4942
+    debug(81, 5) ("icapReqModReadIcapPart: FD %d httpState = %p\n", fd, data);
4943
+    statCounter.syscalls.sock.reads++;
4944
+
4945
+    x = icapReadHeader(fd, icap, &isIcap);
4946
+    if (x < 0) {
4947
+	/* Did not find a proper ICAP response */
4948
+	debug(81, 3) ("ICAP : Error path!\n");
4949
+	icapEntryError(icap, ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR,
4950
+	    errno);
4951
+	comm_close(fd);
4952
+	return;
4953
+    }
4954
+    if (x == 0) {
4955
+	/*
4956
+	 * Waiting for more headers.  Schedule new read hander, but
4957
+	 * don't reset timeout.
4958
+	 */
4959
+	commSetSelect(fd, COMM_SELECT_READ, icapReqModReadIcapPart, icap, 0);
4960
+	return;
4961
+    }
4962
+    /*
4963
+     * Parse the ICAP header
4964
+     */
4965
+    assert(icap->icap_hdr.size);
4966
+    debug(81, 3) ("Read icap header : <%s>\n", icap->icap_hdr.buf);
4967
+    if ((status =
4968
+	    icapParseStatusLine(icap->icap_hdr.buf, icap->icap_hdr.size,
4969
+		&version_major, &version_minor, &str_status)) < 0) {
4970
+	debug(81, 1) ("BAD ICAP status line <%s>\n", icap->icap_hdr.buf);
4971
+	/* is this correct in case of ICAP protocol error? */
4972
+	icapEntryError(icap, ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR,
4973
+	    errno);
4974
+	comm_close(fd);
4975
+	return;
4976
+    };
4977
+    if (200 != status && 201 != status) {
4978
+	debug(81, 1) ("Unsupported status '%d' from ICAP server\n", status);
4979
+	icapEntryError(icap, ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR,
4980
+	    errno);
4981
+	comm_close(fd);
4982
+	return;
4983
+    }
4984
+    icapSetKeepAlive(icap, icap->icap_hdr.buf);
4985
+    if (icapFindHeader(icap->icap_hdr.buf, "Encapsulated:", &start, &end)) {
4986
+	icapParseEncapsulated(icap, start, end);
4987
+    } else {
4988
+	debug(81,
4989
+	    1)
4990
+	    ("WARNING: icapReqModReadIcapPart() did not find 'Encapsulated' header\n");
4991
+    }
4992
+    if (icap->enc.res_hdr > -1)
4993
+	directResponse = 1;
4994
+    else if (icap->enc.res_body > -1)
4995
+	directResponse = 1;
4996
+    else
4997
+	directResponse = 0;
4998
+    debug(81, 3) ("icapReqModReadIcapPart: directResponse=%d\n",
4999
+	directResponse);
5000
+
5001
+    /* Check whether it is a direct reply - if so over to http part */
5002
+    if (directResponse) {
5003
+	debug(81,
5004
+	    3)
5005
+	    ("icapReqModReadIcapPart: FD %d, processing HTTP response for REQMOD!\n",
5006
+	    fd);
5007
+	/* got the reply, no need to come here again */
5008
+	icap->flags.wait_for_reply = 0;
5009
+	icap->flags.got_reply = 1;
5010
+	icapReqModHandoffRespMod(icap);
5011
+	return;
5012
+    }
5013
+    memBufDefInit(&icap->reqmod.hdr_buf);
5014
+    commSetSelect(fd, COMM_SELECT_READ, icapReqModReadHttpHdrs, icap, 0);
5015
+    return;
5016
+}
5017
+
5018
+/*
5019
+ * icapSendReqModDone
5020
+ *
5021
+ * Called after we've sent the ICAP request.  Checks for errors
5022
+ * and installs the handler functions for the next step.
5023
+ */
5024
+static void
5025
+icapSendReqModDone(int fd, char *bufnotused, size_t size, int errflag,
5026
+    void *data)
5027
+{
5028
+    IcapStateData *icap = data;
5029
+
5030
+    debug(81, 5) ("icapSendReqModDone: FD %d: size %d: errflag %d.\n",
5031
+	fd, size, errflag);
5032
+    if (size > 0) {
5033
+	fd_bytes(fd, size, FD_WRITE);
5034
+	kb_incr(&statCounter.icap.all.kbytes_out, size);
5035
+    }
5036
+    if (errflag == COMM_ERR_CLOSING)
5037
+	return;
5038
+    if (errflag) {
5039
+	debug(81, 3) ("icapSendReqModDone: unreachable=1, service=%s\n",
5040
+	    icap->current_service->uri);
5041
+	icapOptSetUnreachable(icap->current_service);
5042
+	icapEntryError(icap, ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR,
5043
+	    errno);
5044
+	comm_close(fd);
5045
+	return;
5046
+    }
5047
+    /* Schedule read reply. */
5048
+    commSetSelect(fd, COMM_SELECT_READ, icapReqModReadIcapPart, icap, 0);
5049
+    /*
5050
+     * Set the read timeout here because it hasn't been set yet.
5051
+     * We only set the read timeout after the request has been
5052
+     * fully written to the server-side.  If we start the timeout
5053
+     * after connection establishment, then we are likely to hit
5054
+     * the timeout for POST/PUT requests that have very large
5055
+     * request bodies.
5056
+     */
5057
+    commSetTimeout(fd, Config.Timeout.read, icapConnectTimeout, icap);
5058
+}
5059
+
5060
+
5061
+/*
5062
+ * icapSendReqMod
5063
+ *
5064
+ * Send the ICAP request, including HTTP request, to the ICAP server
5065
+ * after connection has been established.
5066
+ */
5067
+static void
5068
+icapSendReqMod(int fd, int status, void *data)
5069
+{
5070
+    MemBuf mb;
5071
+    MemBuf mb_hdr;
5072
+    Packer p;
5073
+    IcapStateData *icap = data;
5074
+    char *client_addr;
5075
+    int icap_fd = icap->icap_fd;
5076
+    icap_service *service;
5077
+    CWCB *theCallback;
5078
+
5079
+    debug(81, 5) ("icapSendReqMod FD %d, status %d\n", fd, status);
5080
+    icap->flags.connect_pending = 0;
5081
+
5082
+    if (COMM_OK != status) {
5083
+	debug(81, 1) ("Could not connect to ICAP server %s:%d: %s\n",
5084
+	    icap->current_service->hostname,
5085
+	    icap->current_service->port, xstrerror());
5086
+	debug(81, 3) ("icapSendReqMod: unreachable=1, service=%s\n",
5087
+	    icap->current_service->uri);
5088
+	icapOptSetUnreachable(icap->current_service);
5089
+	icapEntryError(icap, ERR_ICAP_FAILURE, HTTP_SERVICE_UNAVAILABLE, errno);
5090
+	comm_close(fd);
5091
+	return;
5092
+    }
5093
+    fd_table[fd].pconn.uses++;
5094
+    fd_table[fd].pconn.type = 2;
5095
+    if (icap->request->content_length > 0)
5096
+	theCallback = icapReqModSendBodyChunk;
5097
+    else
5098
+	theCallback = icapSendReqModDone;
5099
+
5100
+    memBufDefInit(&mb);
5101
+    memBufDefInit(&mb_hdr);
5102
+    memBufPrintf(&mb_hdr, "%s %s HTTP/%d.%d\r\n",
5103
+	RequestMethodStr[icap->request->method],
5104
+	icap->reqmod.uri,
5105
+	icap->request->http_ver.major, icap->request->http_ver.minor);
5106
+    packerToMemInit(&p, &mb_hdr);
5107
+    httpHeaderPackInto(&icap->request->header, &p);
5108
+    packerClean(&p);
5109
+    memBufAppend(&mb_hdr, crlf, 2);
5110
+    service = icap->current_service;
5111
+    assert(service);
5112
+    client_addr = inet_ntoa(icap->request->client_addr);
5113
+
5114
+    memBufPrintf(&mb, "REQMOD %s ICAP/1.0\r\n", service->uri);
5115
+    memBufPrintf(&mb, "Encapsulated: req-hdr=0");
5116
+    /* TODO: Change the offset using 'request' if needed */
5117
+    if (icap->request->content_length > 0)
5118
+	memBufPrintf(&mb, ", req-body=%d", mb_hdr.size);
5119
+    else
5120
+	memBufPrintf(&mb, ", null-body=%d", mb_hdr.size);
5121
+    memBufAppend(&mb, crlf, 2);
5122
+
5123
+    if (service->flags.need_x_client_ip && Config.icapcfg.send_client_ip)
5124
+	memBufPrintf(&mb, "X-Client-IP: %s\r\n", client_addr);
5125
+
5126
+    if (service->flags.need_x_server_ip && Config.icapcfg.send_server_ip)
5127
+	icapAddOriginIP(&mb, icap->request->host);
5128
+
5129
+    if ((service->flags.need_x_authenticated_user
5130
+	    && Config.icapcfg.send_auth_user)
5131
+	&& (icap->request->auth_user_request != NULL))
5132
+	icapAddAuthUserHeader(&mb, icap->request->auth_user_request);
5133
+    if (service->keep_alive) {
5134
+	icap->flags.keep_alive = 1;
5135
+    } else {
5136
+	icap->flags.keep_alive = 0;
5137
+	memBufAppend(&mb, "Connection: close\r\n", 19);
5138
+    }
5139
+    memBufAppend(&mb, crlf, 2);
5140
+    memBufAppend(&mb, mb_hdr.buf, mb_hdr.size);
5141
+    memBufClean(&mb_hdr);
5142
+
5143
+    debug(81, 5) ("icapSendReqMod: FD %d writing {%s}\n", icap->icap_fd,
5144
+	mb.buf);
5145
+    comm_write_mbuf(icap_fd, mb, theCallback, icap);
5146
+}
5147
+
5148
+/*
5149
+ * icapReqModStart
5150
+ *
5151
+ * Initiate an ICAP REQMOD transaction.  Create and fill in IcapStateData
5152
+ * structure and request a TCP connection to the server.
5153
+ */
5154
+IcapStateData *
5155
+icapReqModStart(icap_service * service, const char *uri, request_t * request,
5156
+    int fd, struct timeval start, struct in_addr log_addr, void *cookie)
5157
+{
5158
+    IcapStateData *icap = NULL;
5159
+
5160
+    debug(81, 3) ("icapReqModStart: type=%d\n", (int) service->type);
5161
+
5162
+    switch (service->type) {
5163
+    case ICAP_SERVICE_REQMOD_PRECACHE:
5164
+	break;
5165
+    default:
5166
+	fatalf("icapReqModStart: unsupported service type '%s'\n",
5167
+	    icap_service_type_str[service->type]);
5168
+	break;
5169
+    }
5170
+
5171
+    if (service->unreachable) {
5172
+	if (service->bypass) {
5173
+	    debug(81,
5174
+		5) ("icapReqModStart: BYPASS because service unreachable: %s\n",
5175
+		service->uri);
5176
+	    return NULL;
5177
+	} else {
5178
+	    debug(81,
5179
+		5) ("icapReqModStart: ERROR  because service unreachable: %s\n",
5180
+		service->uri);
5181
+	    return (IcapStateData *) - 1;
5182
+	}
5183
+    }
5184
+    icap = icapAllocate();
5185
+    if (!icap) {
5186
+	debug(81, 3) ("icapReqModStart: icapAllocate() failed\n");
5187
+	return NULL;
5188
+    }
5189
+    icap->current_service = service;
5190
+    icap->preview_size = service->preview;
5191
+    icap->reqmod.uri = uri;	/* XXX should be xstrdup? */
5192
+    icap->reqmod.start = start;
5193
+    icap->reqmod.log_addr = log_addr;
5194
+    icap->request = requestLink(request);
5195
+    icap->reqmod.hdr_state = 0;
5196
+    icap->reqmod.client_fd = fd;
5197
+    icap->reqmod.client_cookie = cookie;
5198
+    cbdataLock(icap->reqmod.client_cookie);
5199
+
5200
+    if (!icapConnect(icap, icapSendReqMod))
5201
+	return NULL;
5202
+
5203
+    statCounter.icap.all.requests++;
5204
+    debug(81, 3) ("icapReqModStart: returning %p\n", icap);
5205
+    return icap;
5206
+}
5207
+
5208
+/*
5209
+ * icapReqModSendBodyChunk
5210
+ *
5211
+ * A "comm_write" callback.  This is called after comm_write() does
5212
+ * its job to let us know how things went.  If there are no errors,
5213
+ * get another chunk of the body from client_side.
5214
+ */
5215
+static void
5216
+icapReqModSendBodyChunk(int fd, char *bufnotused, size_t size, int errflag,
5217
+    void *data)
5218
+{
5219
+    IcapStateData *icap = data;
5220
+    debug(81, 3) ("icapReqModSendBodyChunk: FD %d wrote %d errflag %d.\n",
5221
+	fd, (int) size, errflag);
5222
+    if (errflag == COMM_ERR_CLOSING)
5223
+	return;
5224
+    if (errflag) {
5225
+	icapEntryError(icap, ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR,
5226
+	    errno);
5227
+	comm_close(fd);
5228
+	return;
5229
+    }
5230
+    clientReadBody(icap->request,
5231
+	memAllocate(MEM_8K_BUF), 8192, icapReqModBodyHandler, icap);
5232
+}
5233
+
5234
+/*
5235
+ * icapReqModBodyHandler
5236
+ *
5237
+ * Called after Squid gets a chunk of the request entity from the
5238
+ * client side.  The body is chunkified and passed to comm_write.
5239
+ * The comm_write callback depends on whether or not this is the
5240
+ * last chunk.
5241
+ */
5242
+static void
5243
+icapReqModBodyHandler(char *buf, ssize_t size, void *data)
5244
+{
5245
+    IcapStateData *icap = data;
5246
+    MemBuf mb;
5247
+    CWCB *theCallback = icapReqModSendBodyChunk;
5248
+    if (size < 0) {
5249
+	debug(81, 1) ("icapReqModBodyHandler: %s\n", xstrerror());
5250
+	memFree8K(buf);
5251
+	return;
5252
+    }
5253
+    memBufDefInit(&mb);
5254
+    debug(81, 3) ("icapReqModBodyHandler: writing chunk size %d\n", size);
5255
+    memBufPrintf(&mb, "%x\r\n", size);
5256
+    if (size)
5257
+	memBufAppend(&mb, buf, size);
5258
+    else
5259
+	theCallback = icapSendReqModDone;
5260
+    memBufAppend(&mb, crlf, 2);
5261
+    memFree8K(buf);
5262
+    comm_write_mbuf(icap->icap_fd, mb, theCallback, icap);
5263
+}
5264
+
5265
+/*
5266
+ * icapReqModReadHttpBody
5267
+ *
5268
+ * The read handler for the client's HTTP connection when reading
5269
+ * message bodies.  Called by comm_select().
5270
+ */
5271
+static void
5272
+icapReqModReadHttpBody(int fd, void *data)
5273
+{
5274
+    IcapStateData *icap = data;
5275
+    int len;
5276
+    debug(81, 3) ("icapReqModReadHttpBody: FD %d called\n", fd);
5277
+    len = memBufRead(fd, &icap->chunk_buf);
5278
+    debug(81, 3) ("icapReqModReadHttpBody: read returns %d\n", len);
5279
+    if (len < 0) {
5280
+	debug(81, 3) ("icapReqModReadHttpBody: FD %d %s\n", fd, xstrerror());
5281
+	if (!ignoreErrno(errno))
5282
+	    icap->flags.reqmod_http_entity_eof = 1;
5283
+    } else if (0 == len) {
5284
+	debug(81, 3) ("icapReqModReadHttpBody: FD %d EOF\n", fd);
5285
+	icap->flags.reqmod_http_entity_eof = 1;
5286
+    } else {
5287
+	fd_bytes(fd, len, FD_READ);
5288
+	kb_incr(&statCounter.icap.all.kbytes_in, len);
5289
+	icap->reqmod.http_entity.bytes_read +=
5290
+	    icapParseChunkedBody(icap,
5291
+	    icapReqModMemBufAppend, &icap->reqmod.http_entity.buf);
5292
+    }
5293
+    if (icap->chunk_size < 0)
5294
+	icap->flags.reqmod_http_entity_eof = 1;
5295
+
5296
+    if (!icap->flags.reqmod_http_entity_eof)
5297
+	commSetSelect(fd, COMM_SELECT_READ, icapReqModReadHttpBody, icap, 0);
5298
+    /*
5299
+     * Notify the other side if it is waiting for data from us
5300
+     */
5301
+    debug(81, 3) ("%s:%d http_entity.callback=%p\n", __FILE__, __LINE__,
5302
+	icap->reqmod.http_entity.callback);
5303
+    debug(81, 3) ("%s:%d http_entity.buf.size=%d\n", __FILE__, __LINE__,
5304
+	icap->reqmod.http_entity.buf.size);
5305
+    if (icap->reqmod.http_entity.callback) {
5306
+	icapReqModPassHttpBody(icap,
5307
+	    icap->reqmod.http_entity.callback_buf,
5308
+	    icap->reqmod.http_entity.callback_bufsize,
5309
+	    icap->reqmod.http_entity.callback,
5310
+	    icap->reqmod.http_entity.callback_data);
5311
+	icap->reqmod.http_entity.callback = NULL;
5312
+	cbdataUnlock(icap->reqmod.http_entity.callback_data);
5313
+    }
5314
+}
5315
+
5316
+/*
5317
+ * icapReqModPassHttpBody
5318
+ *
5319
+ * Called from http.c after request headers have been sent.
5320
+ * This function feeds the http.c module chunks of the request
5321
+ * body that were stored in the http_entity.buf MemBuf.
5322
+ */
5323
+static void
5324
+icapReqModPassHttpBody(IcapStateData * icap, char *buf, size_t size,
5325
+    CBCB * callback, void *cbdata)
5326
+{
5327
+    debug(81, 3) ("icapReqModPassHttpBody: called\n");
5328
+    if (!buf) {
5329
+	debug(81, 1) ("icapReqModPassHttpBody: FD %d called with %p, %d, %p (request aborted)\n",
5330
+	    icap->icap_fd, buf, (int) size, cbdata);
5331
+	comm_close(icap->icap_fd);
5332
+	return;
5333
+    }
5334
+    if (!cbdataValid(cbdata)) {
5335
+	debug(81,
5336
+	    1)
5337
+	    ("icapReqModPassHttpBody: FD %d callback data invalid, closing\n",
5338
+	    icap->icap_fd);
5339
+	comm_close(icap->icap_fd);	/*It is better to be sure that the connection will be  closed..... */
5340
+	/*icapReqModKeepAliveOrClose(icap); */
5341
+	return;
5342
+    }
5343
+    debug(81, 3) ("icapReqModPassHttpBody: entity buf size = %d\n",
5344
+	icap->reqmod.http_entity.buf.size);
5345
+    if (icap->reqmod.http_entity.buf.size) {
5346
+	int copy_sz = icap->reqmod.http_entity.buf.size;
5347
+	if (copy_sz > size)
5348
+	    copy_sz = size;
5349
+	xmemcpy(buf, icap->reqmod.http_entity.buf.buf, copy_sz);
5350
+	/* XXX don't let Alex see this ugliness */
5351
+	xmemmove(icap->reqmod.http_entity.buf.buf,
5352
+	    icap->reqmod.http_entity.buf.buf + copy_sz,
5353
+	    icap->reqmod.http_entity.buf.size - copy_sz);
5354
+	icap->reqmod.http_entity.buf.size -= copy_sz;
5355
+	debug(81, 3) ("icapReqModPassHttpBody: giving %d bytes to other side\n",
5356
+	    copy_sz);
5357
+	callback(buf, copy_sz, cbdata);
5358
+	debug(81, 3) ("icapReqModPassHttpBody: entity buf size now = %d\n",
5359
+	    icap->reqmod.http_entity.buf.size);
5360
+	return;
5361
+    }
5362
+    if (icap->flags.reqmod_http_entity_eof) {
5363
+	debug(81, 3) ("icapReqModPassHttpBody: signalling EOF\n");
5364
+	callback(buf, 0, cbdata);
5365
+	icapReqModKeepAliveOrClose(icap);
5366
+	return;
5367
+    }
5368
+    /*
5369
+     * We have no data for the other side at this point.  Save all
5370
+     * these values and use them when we do have data.
5371
+     */
5372
+    assert(NULL == icap->reqmod.http_entity.callback);
5373
+    icap->reqmod.http_entity.callback = callback;
5374
+    icap->reqmod.http_entity.callback_data = cbdata;
5375
+    icap->reqmod.http_entity.callback_buf = buf;
5376
+    icap->reqmod.http_entity.callback_bufsize = size;
5377
+    cbdataLock(icap->reqmod.http_entity.callback_data);
5378
+}
5379
+
5380
+/*
5381
+ * Body reader handler for use with request->body_reader function
5382
+ * Simple a wrapper for icapReqModPassHttpBody function
5383
+ */
5384
+
5385
+static void
5386
+icapReqModBodyReader(request_t * request, char *buf, size_t size,
5387
+    CBCB * callback, void *cbdata)
5388
+{
5389
+    IcapStateData *icap = request->body_reader_data;
5390
+    icapReqModPassHttpBody(icap, buf, size, callback, cbdata);
5391
+}
5392
+
5393
+/*
5394
+ * icapReqModMemBufAppend
5395
+ *
5396
+ * stupid wrapper to eliminate compiler warnings
5397
+ */
5398
+static void
5399
+icapReqModMemBufAppend(void *data, const char *buf, ssize_t size)
5400
+{
5401
+    memBufAppend(data, buf, size);
5402
+}
5403
Index: src/icap_respmod.c
5404
===================================================================
5405
RCS file: src/icap_respmod.c
5406
diff -N src/icap_respmod.c
5407
--- /dev/null	1 Jan 1970 00:00:00 -0000
5408
+++ src/icap_respmod.c	31 Jan 2007 18:11:15 -0000	1.1.14.8
5409
@@ -0,0 +1,1018 @@
5410
+
5411
+/*
5412
+ * $Id$
5413
+ *
5414
+ * DEBUG: section 81    Internet Content Adaptation Protocol (ICAP) Client
5415
+ * AUTHOR: Geetha Manjunath, Hewlett Packard Company
5416
+ *
5417
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
5418
+ * ----------------------------------------------------------
5419
+ *
5420
+ *  Squid is the result of efforts by numerous individuals from
5421
+ *  the Internet community; see the CONTRIBUTORS file for full
5422
+ *  details.   Many organizations have provided support for Squid's
5423
+ *  development; see the SPONSORS file for full details.  Squid is
5424
+ *  Copyrighted (C) 2001 by the Regents of the University of
5425
+ *  California; see the COPYRIGHT file for full details.  Squid
5426
+ *  incorporates software developed and/or copyrighted by other
5427
+ *  sources; see the CREDITS file for full details.
5428
+ *
5429
+ *  This program is free software; you can redistribute it and/or modify
5430
+ *  it under the terms of the GNU General Public License as published by
5431
+ *  the Free Software Foundation; either version 2 of the License, or
5432
+ *  (at your option) any later version.
5433
+ *  
5434
+ *  This program is distributed in the hope that it will be useful,
5435
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
5436
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
5437
+ *  GNU General Public License for more details.
5438
+ *  
5439
+ *  You should have received a copy of the GNU General Public License
5440
+ *  along with this program; if not, write to the Free Software
5441
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
5442
+ *
5443
+ */
5444
+
5445
+#include "squid.h"
5446
+
5447
+static CWCB icapSendRespModDone;
5448
+static PF icapRespModGobble;
5449
+extern PF icapReadReply;
5450
+static PF icapRespModReadReply;
5451
+static void icapRespModKeepAliveOrClose(IcapStateData * icap);
5452
+static int icapReadReply2(IcapStateData * icap);
5453
+static void icapReadReply3(IcapStateData * icap);
5454
+
5455
+#define EXPECTED_ICAP_HEADER_LEN 256
5456
+const char *crlf = "\r\n";
5457
+
5458
+static void
5459
+getICAPRespModString(MemBuf * mb, int o1, int o2, int o3,
5460
+    const char *client_addr, IcapStateData * icap, const icap_service * service)
5461
+{
5462
+    memBufPrintf(mb, "RESPMOD %s ICAP/1.0\r\nEncapsulated:", service->uri);
5463
+    if (o1 >= 0)
5464
+	memBufPrintf(mb, " req-hdr=%1d", o1);
5465
+    if (o2 >= 0)
5466
+	memBufPrintf(mb, ", res-hdr=%1d", o2);
5467
+    if (o3 >= 0)
5468
+	memBufPrintf(mb, ", res-body=%1d", o3);
5469
+    else
5470
+	memBufPrintf(mb, ", null-body=%1d", -o3);
5471
+    memBufPrintf(mb, crlf);
5472
+
5473
+    if (service->flags.need_x_client_ip && Config.icapcfg.send_client_ip) {
5474
+	memBufPrintf(mb, "X-Client-IP: %s\r\n", client_addr);
5475
+    }
5476
+    if (service->flags.need_x_server_ip && Config.icapcfg.send_server_ip)
5477
+	icapAddOriginIP(mb, icap->request->host);
5478
+
5479
+    if ((service->flags.need_x_authenticated_user
5480
+	    && Config.icapcfg.send_auth_user)
5481
+	&& (icap->request->auth_user_request != NULL)) {
5482
+	icapAddAuthUserHeader(mb, icap->request->auth_user_request);
5483
+    }
5484
+#if NOT_YET_FINISHED
5485
+    if (Config.icapcfg.trailers) {
5486
+	memBufPrintf(mb, "X-TE: trailers\r\n");
5487
+    }
5488
+#endif
5489
+}
5490
+
5491
+static int
5492
+buildRespModHeader(MemBuf * mb, IcapStateData * icap)
5493
+{
5494
+    MemBuf mb_hdr;
5495
+    char *client_addr;
5496
+    int o2 = 0;
5497
+    int o3 = 0;
5498
+    int hlen;
5499
+    int consumed;
5500
+    icap_service *service;
5501
+    HttpReply *r;
5502
+
5503
+    if (icap->respmod.req_hdr_copy.size > 4 && strncmp(icap->respmod.req_hdr_copy.buf, "HTTP/", 5)) {
5504
+	debug(81, 3) ("buildRespModHeader: Non-HTTP-compliant header: '%s'\n", icap->respmod.req_hdr_copy.buf);
5505
+	/*
5506
+	 *Possible we can consider that we did not have http responce headers 
5507
+	 *(maybe HTTP 0.9 protocol), lets returning -1...
5508
+	 */
5509
+	consumed = -1;
5510
+	o2 = -1;
5511
+	memBufDefInit(&mb_hdr);
5512
+	httpBuildRequestPrefix(icap->request, icap->request,
5513
+	    icap->respmod.entry, &mb_hdr, icap->http_flags);
5514
+	o3 = mb_hdr.size;
5515
+    } else {
5516
+
5517
+	hlen = headersEnd(icap->respmod.req_hdr_copy.buf,
5518
+	    icap->respmod.req_hdr_copy.size);
5519
+	debug(81, 3) ("buildRespModHeader: headersEnd = %d(%s)\n", hlen, icap->respmod.req_hdr_copy.buf);
5520
+	if (0 == hlen)
5521
+	    return 0;
5522
+
5523
+	consumed = hlen;
5524
+	debug(81, 3) ("buildRespModHeader: consumed = %d (from %d)\n", consumed, icap->respmod.req_hdr_copy.size);
5525
+
5526
+
5527
+	/*
5528
+	 * now, truncate our req_hdr_copy at the header end.
5529
+	 * this 'if' statement might be unncessary?
5530
+	 */
5531
+	if (hlen < icap->respmod.req_hdr_copy.size)
5532
+	    icap->respmod.req_hdr_copy.size = hlen;
5533
+
5534
+	/* Copy request header */
5535
+	memBufDefInit(&mb_hdr);
5536
+	httpBuildRequestPrefix(icap->request, icap->request,
5537
+	    icap->respmod.entry, &mb_hdr, icap->http_flags);
5538
+	o2 = mb_hdr.size;
5539
+
5540
+	/* Copy response header - Append to request header mbuffer */
5541
+	memBufAppend(&mb_hdr,
5542
+	    icap->respmod.req_hdr_copy.buf, icap->respmod.req_hdr_copy.size);
5543
+	o3 = mb_hdr.size;
5544
+    }
5545
+
5546
+    service = icap->current_service;
5547
+    assert(service);
5548
+    client_addr = inet_ntoa(icap->request->client_addr);
5549
+
5550
+    r = httpReplyCreate();
5551
+    httpReplyParse(r, icap->respmod.req_hdr_copy.buf,
5552
+	icap->respmod.req_hdr_copy.size);
5553
+    icap->respmod.res_body_sz = httpReplyBodySize(icap->request->method, r);
5554
+    httpReplyDestroy(r);
5555
+    if (icap->respmod.res_body_sz)
5556
+	getICAPRespModString(mb, 0, o2, o3, client_addr, icap, service);
5557
+    else
5558
+	getICAPRespModString(mb, 0, o2, -o3, client_addr, icap, service);
5559
+    if (Config.icapcfg.preview_enable)
5560
+	if (icap->preview_size >= 0) {
5561
+	    memBufPrintf(mb, "Preview: %d\r\n", icap->preview_size);
5562
+	    icap->flags.preview_done = 0;
5563
+	}
5564
+    if (service->keep_alive) {
5565
+	icap->flags.keep_alive = 1;
5566
+	memBufAppend(mb, "Connection: keep-alive\r\n", 24);
5567
+    } else {
5568
+	icap->flags.keep_alive = 0;
5569
+	memBufAppend(mb, "Connection: close\r\n", 19);
5570
+    }
5571
+    memBufAppend(mb, crlf, 2);
5572
+    memBufAppend(mb, mb_hdr.buf, mb_hdr.size);
5573
+    memBufClean(&mb_hdr);
5574
+    return consumed;
5575
+}
5576
+
5577
+void
5578
+icapRespModAddResponceHeaders(IcapStateData * icap, char *buf, int len)
5579
+{
5580
+    if (memBufIsNull(&icap->respmod.req_hdr_copy))
5581
+	memBufDefInit(&icap->respmod.req_hdr_copy);
5582
+    memBufAppend(&icap->respmod.req_hdr_copy, buf, len);
5583
+    if (len && icap->flags.copy_response) {
5584
+	if (memBufIsNull(&icap->respmod.resp_copy))
5585
+	    memBufDefInit(&icap->respmod.resp_copy);
5586
+	memBufAppend(&icap->respmod.resp_copy, buf, len);
5587
+    }
5588
+}
5589
+
5590
+void
5591
+icapRespModAddBodyData(IcapStateData * icap, char *buf, int len)
5592
+{
5593
+    if (icap->flags.no_content) {
5594
+	/*
5595
+	 * ICAP server said there are no modifications to make, so
5596
+	 * just append this data to the StoreEntry
5597
+	 */
5598
+	if (icap->respmod.resp_copy.size) {
5599
+	    /*
5600
+	     * first copy the data that we already sent to the ICAP server
5601
+	     */
5602
+	    memBufAppend(&icap->chunk_buf,
5603
+		icap->respmod.resp_copy.buf, icap->respmod.resp_copy.size);
5604
+	    icap->respmod.resp_copy.size = 0;
5605
+	}
5606
+	if (len) {
5607
+	    /*
5608
+	     * also copy any new data from the HTTP side
5609
+	     */
5610
+	    memBufAppend(&icap->chunk_buf, buf, len);
5611
+	}
5612
+	(void) icapReadReply2(icap);
5613
+	return;
5614
+    }
5615
+#if SUPPORT_ICAP_204 || ICAP_PREVIEW
5616
+    /*
5617
+     * make a copy of the response in case ICAP server gives us a 204
5618
+     */
5619
+    /*
5620
+     * This piece of code is problematic for 204 responces outside preview.
5621
+     * The icap->respmod.resp_copy continues to filled until we had responce
5622
+     * If the icap server waits to gets all data before sends its responce 
5623
+     * then we are puting all downloading object to the main system memory.
5624
+     * My opinion is that 204 responces outside preview must be disabled .....
5625
+     * /chtsanti
5626
+     */
5627
+
5628
+    if (len && icap->flags.copy_response) {
5629
+	if (memBufIsNull(&icap->respmod.resp_copy))
5630
+	    memBufDefInit(&icap->respmod.resp_copy);
5631
+	memBufAppend(&icap->respmod.resp_copy, buf, len);
5632
+    }
5633
+#endif
5634
+
5635
+    if (buf && len > 0)
5636
+	memBufAppend(&icap->respmod.buffer, buf, len);
5637
+}
5638
+
5639
+
5640
+void
5641
+icapSendRespMod(IcapStateData * icap, int theEnd)
5642
+{
5643
+    MemBuf mb;
5644
+#if ICAP_PREVIEW
5645
+    int size;
5646
+    const int preview_size = icap->preview_size;
5647
+#endif
5648
+    if (icap->flags.no_content) {
5649
+	return;
5650
+    }
5651
+    debug(81, 5) ("icapSendRespMod: FD %d, theEnd %d\n",
5652
+	icap->icap_fd, theEnd);
5653
+
5654
+    /*
5655
+     * httpReadReply is going to call us with a chunk and then
5656
+     * right away again with an EOF if httpPconnTransferDone() is true.
5657
+     * Since the first write is already dispatched, we'll have to 
5658
+     * hack this in somehow.
5659
+     */
5660
+    if (icap->flags.write_pending) {
5661
+	debug(81, 3) ("icapSendRespMod: oops, write_pending=1\n");
5662
+	assert(theEnd);
5663
+	return;
5664
+    }
5665
+    if (!cbdataValid(icap)) {
5666
+	debug(81, 3) ("icapSendRespMod: failed to establish connection?\n");
5667
+	return;
5668
+    }
5669
+    memBufDefInit(&mb);
5670
+
5671
+    if (icap->sc == 0) {
5672
+	// http connection has been closed without sending us anything
5673
+	if (icap->respmod.req_hdr_copy.size == 0 && theEnd == 1) {
5674
+	    ErrorState *err;
5675
+	    err = errorCon(ERR_INVALID_RESP, HTTP_BAD_GATEWAY, icap->request);
5676
+	    errorAppendEntry(icap->respmod.entry, err);
5677
+	    comm_close(icap->icap_fd);
5678
+	    return;
5679
+	}
5680
+	/* No data sent yet. Start with headers */
5681
+	icap->sc = buildRespModHeader(&mb, icap);
5682
+	assert(icap->sc != 0);
5683
+    }
5684
+    if (theEnd) {
5685
+	if (icap->respmod.res_body_sz)
5686
+	    icap->flags.send_zero_chunk = 1;
5687
+	icap->flags.http_server_eof = 1;
5688
+    }
5689
+#if ICAP_PREVIEW
5690
+    if (preview_size < 0 || !Config.icapcfg.preview_enable)	/* preview feature off */
5691
+	icap->flags.preview_done = 1;
5692
+
5693
+    if (!icap->flags.preview_done) {
5694
+	/* preview not yet sent */
5695
+	if (icap->respmod.buffer.size > preview_size || theEnd) {
5696
+	    /* we got enough bytes for preview or this is the last call */
5697
+	    /* add preview preview now */
5698
+	    if (icap->respmod.buffer.size > 0) {
5699
+		size = icap->respmod.buffer.size;
5700
+		if (size > preview_size)
5701
+		    size = preview_size;
5702
+		memBufPrintf(&mb, "%x\r\n", size);
5703
+		memBufAppend(&mb, icap->respmod.buffer.buf, size);
5704
+		memBufAppend(&mb, crlf, 2);
5705
+		icap->sc += size;
5706
+	    }
5707
+	    if (icap->respmod.buffer.size <= preview_size) {
5708
+		/* content length is less than preview size+1 */
5709
+		if (icap->respmod.res_body_sz)
5710
+		    memBufAppend(&mb, "0; ieof\r\n\r\n", 11);
5711
+		memBufReset(&icap->respmod.buffer);	/* will now be used for other data */
5712
+	    } else {
5713
+		char ch;
5714
+		memBufAppend(&mb, "0\r\n\r\n", 5);
5715
+		/* end of preview, wait for continue or 204 signal */
5716
+		/* copy the extra byte and all other data to the icap buffer */
5717
+		/* so that it can be handled next time */
5718
+		ch = icap->respmod.buffer.buf[preview_size];
5719
+		xmemmove(icap->respmod.buffer.buf,
5720
+		    icap->respmod.buffer.buf + preview_size,
5721
+		    icap->respmod.buffer.size - preview_size);
5722
+		icap->respmod.buffer.size = icap->respmod.buffer.size - preview_size;
5723
+		icap->respmod.buffer.buf[icap->respmod.buffer.size] = '\0';
5724
+		debug(81,
5725
+		    3)
5726
+		    ("icapSendRespMod: FD %d: sending preview and keeping %d bytes in internal buf.\n",
5727
+		    icap->icap_fd, icap->respmod.buffer.size);
5728
+	    }
5729
+	    icap->flags.preview_done = 1;
5730
+	    icap->flags.wait_for_preview_reply = 1;
5731
+	}
5732
+    } else if (icap->flags.wait_for_preview_reply) {
5733
+	memBufClean(&mb);
5734
+	return;
5735
+    } else
5736
+#endif
5737
+    {
5738
+	/* after preview completed and ICAP preview response received */
5739
+	/* there may still be some data in the buffer */
5740
+	if (icap->respmod.buffer.size > 0) {
5741
+	    memBufPrintf(&mb, "%x\r\n", icap->respmod.buffer.size);
5742
+	    memBufAppend(&mb, icap->respmod.buffer.buf,
5743
+		icap->respmod.buffer.size);
5744
+	    memBufAppend(&mb, crlf, 2);
5745
+	    icap->sc += icap->respmod.buffer.size;
5746
+	    memBufReset(&icap->respmod.buffer);
5747
+	}
5748
+	if (icap->flags.send_zero_chunk) {
5749
+	    /* send zero end chunk */
5750
+	    icap->flags.send_zero_chunk = 0;
5751
+	    icap->flags.http_server_eof = 1;
5752
+	    memBufAppend(&mb, "0\r\n\r\n", 5);
5753
+	}
5754
+	/* wait for data coming from ICAP server as soon as we sent something */
5755
+	/* but of course only until we got the response header */
5756
+	if (!icap->flags.got_reply)
5757
+	    icap->flags.wait_for_reply = 1;
5758
+    }
5759
+    commSetTimeout(icap->icap_fd, -1, NULL, NULL);
5760
+
5761
+    if (!mb.size) {
5762
+	memBufClean(&mb);
5763
+	return;
5764
+    }
5765
+    debug(81, 5) ("icapSendRespMod: FD %d writing {%s}\n", icap->icap_fd,
5766
+	mb.buf);
5767
+    icap->flags.write_pending = 1;
5768
+    comm_write_mbuf(icap->icap_fd, mb, icapSendRespModDone, icap);
5769
+}
5770
+
5771
+static void
5772
+icapRespModReadReply(int fd, void *data)
5773
+{
5774
+    IcapStateData *icap = data;
5775
+    int version_major, version_minor;
5776
+    const char *str_status;
5777
+    int x;
5778
+    int status = 0;
5779
+    int isIcap = 0;
5780
+    int directResponse = 0;
5781
+    ErrorState *err;
5782
+    const char *start;
5783
+    const char *end;
5784
+
5785
+    debug(81, 5) ("icapRespModReadReply: FD %d data = %p\n", fd, data);
5786
+    statCounter.syscalls.sock.reads++;
5787
+
5788
+    x = icapReadHeader(fd, icap, &isIcap);
5789
+    if (x < 0) {
5790
+	/* Did not find a proper ICAP response */
5791
+	debug(81, 3) ("ICAP : Error path!\n");
5792
+	err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR, icap->request);
5793
+	err->xerrno = errno;
5794
+	errorAppendEntry(icap->respmod.entry, err);
5795
+	comm_close(fd);
5796
+	return;
5797
+    }
5798
+    if (x == 0) {
5799
+	/*
5800
+	 * Waiting for more headers.  Schedule new read hander, but
5801
+	 * don't reset timeout.
5802
+	 */
5803
+	commSetSelect(fd, COMM_SELECT_READ, icapRespModReadReply, icap, 0);
5804
+	return;
5805
+    }
5806
+    /*
5807
+     * Parse the ICAP header
5808
+     */
5809
+    assert(icap->icap_hdr.size);
5810
+    debug(81, 3) ("Parse icap header : <%s>\n", icap->icap_hdr.buf);
5811
+    if ((status =
5812
+	    icapParseStatusLine(icap->icap_hdr.buf, icap->icap_hdr.size,
5813
+		&version_major, &version_minor, &str_status)) < 0) {
5814
+	debug(81, 1) ("BAD ICAP status line <%s>\n", icap->icap_hdr.buf);
5815
+	/* is this correct in case of ICAP protocol error? */
5816
+	err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR, icap->request);
5817
+	err->xerrno = errno;
5818
+	errorAppendEntry(icap->respmod.entry, err);
5819
+	comm_close(fd);
5820
+	return;
5821
+    };
5822
+    /*  OK here we have responce. Lets stop filling the 
5823
+     *  icap->respmod.resp_copy buffer ....
5824
+     */
5825
+    icap->flags.copy_response = 0;
5826
+
5827
+    icapSetKeepAlive(icap, icap->icap_hdr.buf);
5828
+#if ICAP_PREVIEW
5829
+    if (icap->flags.wait_for_preview_reply) {
5830
+	if (100 == status) {
5831
+	    debug(81, 5) ("icapRespModReadReply: 100 Continue received\n");
5832
+	    icap->flags.wait_for_preview_reply = 0;
5833
+	    /* if http_server_eof
5834
+	     * call again icapSendRespMod to handle data that
5835
+	     * was received while waiting for this ICAP response
5836
+	     * else let http to call icapSendRespMod when new data arrived
5837
+	     */
5838
+	    if (icap->flags.http_server_eof)
5839
+		icapSendRespMod(icap, 0);
5840
+	    /*
5841
+	     * reset the header to send the rest of the preview
5842
+	     */
5843
+	    if (!memBufIsNull(&icap->icap_hdr))
5844
+		memBufReset(&icap->icap_hdr);
5845
+
5846
+	    /*We do n't need it any more ....... */
5847
+	    if (!memBufIsNull(&icap->respmod.resp_copy))
5848
+		memBufClean(&icap->respmod.resp_copy);
5849
+
5850
+	    return;
5851
+	}
5852
+	if (204 == status) {
5853
+	    debug(81,
5854
+		5) ("icapRespModReadReply: 204 No modification received\n");
5855
+	    icap->flags.wait_for_preview_reply = 0;
5856
+	}
5857
+    }
5858
+#endif /*ICAP_PREVIEW */
5859
+
5860
+#if SUPPORT_ICAP_204 || ICAP_PREVIEW
5861
+    if (204 == status) {
5862
+	debug(81, 3) ("got 204 status from ICAP server\n");
5863
+	icapRespModKeepAliveOrClose(icap);
5864
+
5865
+	debug(81, 3) ("setting icap->flags.no_content\n");
5866
+	icap->flags.no_content = 1;
5867
+	/*
5868
+	 * copy the response already written to the ICAP server
5869
+	 */
5870
+	debug(81, 3) ("copying %d bytes from resp_copy to chunk_buf\n",
5871
+	    icap->respmod.resp_copy.size);
5872
+	memBufAppend(&icap->chunk_buf,
5873
+	    icap->respmod.resp_copy.buf, icap->respmod.resp_copy.size);
5874
+	icap->respmod.resp_copy.size = 0;
5875
+	if (icapReadReply2(icap) < 0)
5876
+	    icapStateFree(-1, icap);
5877
+
5878
+	/*
5879
+	 * XXX ideally want to clean icap->respmod.resp_copy here
5880
+	 * XXX ideally want to "close" ICAP server connection here
5881
+	 * OK do it....
5882
+	 */
5883
+	if (!memBufIsNull(&icap->respmod.resp_copy))
5884
+	    memBufClean(&icap->respmod.resp_copy);
5885
+	return;
5886
+    }
5887
+#endif
5888
+    if (200 != status && 201 != status) {
5889
+	debug(81, 1) ("Unsupported status '%d' from ICAP server\n", status);
5890
+	/* Did not find a proper ICAP response */
5891
+	err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR, icap->request);
5892
+	err->xerrno = errno;
5893
+	errorAppendEntry(icap->respmod.entry, err);
5894
+	comm_close(fd);
5895
+	return;
5896
+    }
5897
+    if (icapFindHeader(icap->icap_hdr.buf, "Encapsulated:", &start, &end)) {
5898
+	icapParseEncapsulated(icap, start, end);
5899
+    } else {
5900
+	debug(81,
5901
+	    1)
5902
+	    ("WARNING: icapRespModReadReply() did not find 'Encapsulated' header\n");
5903
+    }
5904
+    if (icap->enc.res_hdr > -1)
5905
+	directResponse = 1;
5906
+    else if (icap->enc.res_body > -1)
5907
+	directResponse = 1;
5908
+    else
5909
+	directResponse = 0;
5910
+
5911
+    /*
5912
+     * "directResponse" is the normal case here.  If we don't have
5913
+     * a response header or body, it is an error.
5914
+     */
5915
+    if (!directResponse) {
5916
+	/* Did not find a proper ICAP response */
5917
+	debug(81, 3) ("ICAP : Error path!\n");
5918
+	err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR, icap->request);
5919
+	err->xerrno = errno;
5920
+	errorAppendEntry(icap->respmod.entry, err);
5921
+	comm_close(fd);
5922
+	return;
5923
+    }
5924
+    /* got the reply, no need to come here again */
5925
+    icap->flags.wait_for_reply = 0;
5926
+    icap->flags.got_reply = 1;
5927
+    /* Next, gobble any data before the HTTP response starts */
5928
+    if (icap->enc.res_hdr > -1)
5929
+	icap->bytes_to_gobble = icap->enc.res_hdr;
5930
+    commSetSelect(fd, COMM_SELECT_READ, icapRespModGobble, icap, 0);
5931
+}
5932
+
5933
+
5934
+/*
5935
+ * Gobble up (read) some bytes until we get to the start of the body
5936
+ */
5937
+static void
5938
+icapRespModGobble(int fd, void *data)
5939
+{
5940
+    IcapStateData *icap = data;
5941
+    int len;
5942
+    LOCAL_ARRAY(char, junk, SQUID_TCP_SO_RCVBUF);
5943
+    debug(81, 3) ("icapRespModGobble: FD %d gobbling %d bytes\n", fd,
5944
+	icap->bytes_to_gobble);
5945
+    len = FD_READ_METHOD(fd, junk, icap->bytes_to_gobble);
5946
+    debug(81, 3) ("icapRespModGobble: gobbled %d bytes\n", len);
5947
+    if (len < 0) {
5948
+	/* XXX error */
5949
+	abort();
5950
+    }
5951
+    icap->bytes_to_gobble -= len;
5952
+    if (icap->bytes_to_gobble)
5953
+	commSetSelect(fd, COMM_SELECT_READ, icapRespModGobble, icap, 0);
5954
+    else
5955
+	icapReadReply(fd, icap);
5956
+}
5957
+
5958
+
5959
+static void
5960
+icapSendRespModDone(int fd, char *bufnotused, size_t size, int errflag,
5961
+    void *data)
5962
+{
5963
+    IcapStateData *icap = data;
5964
+    ErrorState *err;
5965
+
5966
+    icap->flags.write_pending = 0;
5967
+    debug(81, 5) ("icapSendRespModDone: FD %d: size %d: errflag %d.\n",
5968
+	fd, size, errflag);
5969
+    if (size > 0) {
5970
+	fd_bytes(fd, size, FD_WRITE);
5971
+	kb_incr(&statCounter.icap.all.kbytes_out, size);
5972
+    }
5973
+    if (errflag == COMM_ERR_CLOSING)
5974
+	return;
5975
+    if (errflag) {
5976
+	if (cbdataValid(icap))
5977
+	    err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR, icap->request);
5978
+	else
5979
+	    err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR, NULL);
5980
+	err->xerrno = errno;
5981
+	storeEntryReset(icap->respmod.entry);
5982
+	errorAppendEntry(icap->respmod.entry, err);
5983
+	comm_close(fd);
5984
+	return;
5985
+    }
5986
+    if (EBIT_TEST(icap->respmod.entry->flags, ENTRY_ABORTED)) {
5987
+	debug(81, 3) ("icapSendRespModDone: Entry Aborded\n");
5988
+	comm_close(fd);
5989
+	return;
5990
+    }
5991
+    if (icap->flags.send_zero_chunk) {
5992
+	debug(81,
5993
+	    3) ("icapSendRespModDone: I'm supposed to send zero chunk now\n");
5994
+	icap->flags.send_zero_chunk = 0;
5995
+	icapSendRespMod(icap, 1);
5996
+	return;
5997
+    }
5998
+    if (icap->flags.wait_for_preview_reply || icap->flags.wait_for_reply) {
5999
+	/* Schedule reading the ICAP response */
6000
+	debug(81,
6001
+	    3)
6002
+	    ("icapSendRespModDone: FD %d: commSetSelect on read icapRespModReadReply.\n",
6003
+	    fd);
6004
+	commSetSelect(fd, COMM_SELECT_READ, icapRespModReadReply, icap, 0);
6005
+#if 1
6006
+	commSetTimeout(fd, Config.Timeout.read, icapReadTimeout, icap);
6007
+	commSetDefer(fd, fwdCheckDeferRead, icap->respmod.entry);
6008
+#else
6009
+	if (icap->flags.wait_for_preview_reply || icap->flags.http_server_eof) {
6010
+	    /*
6011
+	     * Set the read timeout only after all data has been sent
6012
+	     * or we are waiting for a preview response
6013
+	     * If the ICAP server does not return any data till all data
6014
+	     * has been sent, we are likely to hit the timeout for large
6015
+	     * HTTP bodies
6016
+	     */
6017
+	    commSetTimeout(fd, Config.Timeout.read, icapReadTimeout, icap);
6018
+	}
6019
+#endif
6020
+    }
6021
+}
6022
+
6023
+void
6024
+icapConnectOver(int fd, int status, void *data)
6025
+{
6026
+    ErrorState *err;
6027
+    IcapStateData *icap = data;
6028
+    debug(81, 3) ("icapConnectOver: FD %d, status=%d\n", fd, status);
6029
+    icap->flags.connect_pending = 0;
6030
+    if (status < 0) {
6031
+	err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR, icap->request);
6032
+	err->xerrno = errno;
6033
+	errorAppendEntry(icap->respmod.entry, err);
6034
+	comm_close(fd);
6035
+	debug(81, 3) ("icapConnectOver: status < 0, unreachable=1\n");
6036
+	icapOptSetUnreachable(icap->current_service);
6037
+	return;
6038
+    }
6039
+    fd_table[fd].pconn.uses++;
6040
+    fd_table[fd].pconn.type = 2;
6041
+    commSetSelect(fd, COMM_SELECT_READ, icapRespModReadReply, icap, 0);
6042
+}
6043
+
6044
+
6045
+
6046
+IcapStateData *
6047
+icapRespModStart(icap_service_t type, request_t * request, StoreEntry * entry,
6048
+    http_state_flags http_flags)
6049
+{
6050
+    IcapStateData *icap = NULL;
6051
+    CNCB *theCallback = NULL;
6052
+    icap_service *service = NULL;
6053
+
6054
+    debug(81, 3) ("icapRespModStart: type=%d\n", (int) type);
6055
+    assert(type >= 0 && type < ICAP_SERVICE_MAX);
6056
+
6057
+    service = icapService(type, request);
6058
+    if (!service) {
6059
+	debug(81, 3) ("icapRespModStart: no service found\n");
6060
+	return NULL;		/* no service found */
6061
+    }
6062
+    if (service->unreachable) {
6063
+	if (service->bypass) {
6064
+	    debug(81,
6065
+		5)
6066
+		("icapRespModStart: BYPASS because service unreachable: %s\n",
6067
+		service->uri);
6068
+	    return NULL;
6069
+	} else {
6070
+	    debug(81,
6071
+		5)
6072
+		("icapRespModStart: ERROR  because service unreachable: %s\n",
6073
+		service->uri);
6074
+	    return (IcapStateData *) - 1;
6075
+	}
6076
+    }
6077
+    switch (type) {
6078
+	/* TODO: When we support more than ICAP_SERVICE_RESPMOD_PRECACHE, we needs to change
6079
+	 * this switch, because callbacks isn't keep */
6080
+    case ICAP_SERVICE_RESPMOD_PRECACHE:
6081
+	theCallback = icapConnectOver;
6082
+	break;
6083
+    default:
6084
+	fatalf("icapRespModStart: unsupported service type '%s'\n",
6085
+	    icap_service_type_str[type]);
6086
+	break;
6087
+    }
6088
+
6089
+    icap = icapAllocate();
6090
+    if (!icap) {
6091
+	debug(81, 3) ("icapRespModStart: icapAllocate() failed\n");
6092
+	return NULL;
6093
+    }
6094
+    icap->request = requestLink(request);
6095
+    icap->respmod.entry = entry;
6096
+    if (entry)
6097
+	storeLockObject(entry);
6098
+    icap->http_flags = http_flags;
6099
+    memBufDefInit(&icap->respmod.buffer);
6100
+    memBufDefInit(&icap->chunk_buf);
6101
+
6102
+    icap->current_service = service;
6103
+    icap->preview_size = service->preview;
6104
+
6105
+    /* 
6106
+     * Don't create socket to the icap server now, but only for the first
6107
+     * packet receive from the http server. This will resolve all timeout
6108
+     * between the web server and icap server.
6109
+     */
6110
+    debug(81, 3) ("icapRespModStart: setting connect_requested to 0\n");
6111
+    icap->flags.connect_requested = 0;
6112
+
6113
+    /*
6114
+     * make a copy the HTTP response that we send to the ICAP server in
6115
+     * case it turns out to be a 204
6116
+     */
6117
+#ifdef SUPPORT_ICAP_204
6118
+    icap->flags.copy_response = 1;
6119
+#elif ICAP_PREVIEW
6120
+    if (preview_size < 0 || !Config.icapcfg.preview_enable)
6121
+	icap->flags.copy_response = 0;
6122
+    else
6123
+	icap->flags.copy_response = 1;
6124
+#else
6125
+    icap->flags.copy_response = 0;
6126
+#endif
6127
+
6128
+    statCounter.icap.all.requests++;
6129
+    debug(81, 3) ("icapRespModStart: returning %p\n", icap);
6130
+    return icap;
6131
+}
6132
+
6133
+static int
6134
+icapHttpReplyHdrState(IcapStateData * icap)
6135
+{
6136
+    assert(icap);
6137
+    if (NULL == icap->httpState)
6138
+	return 0;
6139
+    return icap->httpState->reply_hdr_state;
6140
+}
6141
+
6142
+static size_t
6143
+icapProcessHttpReplyHeader(IcapStateData * icap, const char *buf, int size)
6144
+{
6145
+    size_t done;
6146
+    if (NULL == icap->httpState) {
6147
+	icap->httpState = cbdataAlloc(HttpStateData);
6148
+	icap->httpState->request = requestLink(icap->request);
6149
+	icap->httpState->orig_request = requestLink(icap->request);
6150
+	icap->httpState->entry = icap->respmod.entry;
6151
+	storeLockObject(icap->httpState->entry);	/* lock it */
6152
+    }
6153
+    done = httpProcessReplyHeader(icap->httpState, buf, size);
6154
+    if (2 == icap->httpState->reply_hdr_state)
6155
+	EBIT_CLR(icap->httpState->entry->flags, ENTRY_FWD_HDR_WAIT);
6156
+    return done;
6157
+}
6158
+
6159
+/*
6160
+ * icapRespModKeepAliveOrClose
6161
+ *
6162
+ * Called when we are done reading from the ICAP server.
6163
+ * Either close the connection or keep it open for a future
6164
+ * transaction.
6165
+ */
6166
+static void
6167
+icapRespModKeepAliveOrClose(IcapStateData * icap)
6168
+{
6169
+    int fd = icap->icap_fd;
6170
+    if (fd < 0)
6171
+	return;
6172
+    debug(81, 3) ("%s:%d FD %d looks good, keeping alive\n", __FILE__, __LINE__,
6173
+	fd);
6174
+    commSetDefer(fd, NULL, NULL);
6175
+    commSetTimeout(fd, -1, NULL, NULL);
6176
+    commSetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0);
6177
+    comm_remove_close_handler(fd, icapStateFree, icap);
6178
+    icap->icap_fd = -1;
6179
+    if (!icap->flags.keep_alive) {
6180
+	debug(81, 3) ("%s:%d keep_alive not set, closing\n", __FILE__,
6181
+	    __LINE__);
6182
+	comm_close(fd);
6183
+	return;
6184
+    } else {
6185
+	pconnPush(fd, icap->current_service->hostname, icap->current_service->port, NULL, NULL, 0);
6186
+    }
6187
+}
6188
+
6189
+
6190
+
6191
+/*
6192
+ * copied from httpPconnTransferDone
6193
+ *
6194
+ */
6195
+static int
6196
+icapPconnTransferDone(int fd, IcapStateData * icap)
6197
+{
6198
+    debug(81, 3) ("icapPconnTransferDone: FD %d\n", fd);
6199
+    /*
6200
+     * Be careful with 204 responses.  Normally we are done when we
6201
+     * see the zero-end chunk, but that won't happen for 204s, so we
6202
+     * use an EOF indicator on the HTTP side instead.
6203
+     */
6204
+    if (icap->flags.no_content && icap->flags.http_server_eof) {
6205
+	debug(81, 5) ("icapPconnTransferDone: no content, ret 1\n");
6206
+	return 1;
6207
+    }
6208
+    if (icapHttpReplyHdrState(icap) != 2) {
6209
+	debug(81,
6210
+	    5) ("icapPconnTransferDone: didn't see end of HTTP hdrs, ret 0\n");
6211
+	return 0;
6212
+    }
6213
+    if (icap->enc.null_body > -1) {
6214
+	debug(81, 5) ("icapPconnTransferDone: no message body, ret 1\n");
6215
+	return 1;
6216
+    }
6217
+    if (icap->chunk_size == -2) {	//AI: was != -2 ; and change content with bottom
6218
+	/* zero end chunk reached */
6219
+	debug(81, 5) ("icapPconnTransferDone: got zero end chunk\n");
6220
+	return 1;
6221
+    }
6222
+    debug(81, 5) ("icapPconnTransferDone: didnt get zero end chunk yet\n");	//AI: change with second top condition
6223
+
6224
+    return 0;
6225
+}
6226
+
6227
+static int
6228
+icapExpectedHttpReplyHdrSize(IcapStateData * icap)
6229
+{
6230
+    if (icap->enc.res_body > -1 && icap->enc.res_hdr > -1)
6231
+	return (icap->enc.res_body - icap->enc.res_hdr);
6232
+    if (icap->enc.null_body > -1 && icap->enc.res_hdr > -1)
6233
+	return icap->enc.null_body - icap->enc.res_hdr;
6234
+    /*The case we did not get res_hdr ..... */
6235
+    if (icap->enc.res_body > -1)
6236
+	return icap->enc.res_body;
6237
+    if (icap->enc.null_body > -1)
6238
+	return icap->enc.null_body;
6239
+    return -1;
6240
+}
6241
+
6242
+/*
6243
+ * copied from httpReadReply()
6244
+ *
6245
+ * by the time this is called, the ICAP headers have already
6246
+ * been read.
6247
+ */
6248
+void
6249
+icapReadReply(int fd, void *data)
6250
+{
6251
+    IcapStateData *icap = data;
6252
+    StoreEntry *entry = icap->respmod.entry;
6253
+    const request_t *request = icap->request;
6254
+    int len;
6255
+    debug(81, 5) ("icapReadReply: FD %d: icap %p.\n", fd, data);
6256
+    if (icap->flags.no_content && !icap->flags.http_server_eof) {	//AI
6257
+
6258
+	return;
6259
+    }
6260
+    if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
6261
+	comm_close(fd);
6262
+	return;
6263
+    }
6264
+    errno = 0;
6265
+    statCounter.syscalls.sock.reads++;
6266
+    len = memBufRead(fd, &icap->chunk_buf);
6267
+    debug(81, 5) ("icapReadReply: FD %d: len %d.\n", fd, len);
6268
+    if (len > 0) {
6269
+	fd_bytes(fd, len, FD_READ);
6270
+	kb_incr(&statCounter.icap.all.kbytes_in, len);
6271
+	commSetTimeout(fd, Config.Timeout.read, icapReadTimeout, icap);
6272
+	if (icap->chunk_buf.size < icap->chunk_buf.capacity) {
6273
+	    *(icap->chunk_buf.buf + icap->chunk_buf.size) = '\0';
6274
+	    debug(81, 9) ("{%s}\n", icap->chunk_buf.buf);
6275
+	}
6276
+    }
6277
+    if (len <= 0) {
6278
+	debug(81, 2) ("icapReadReply: FD %d: read failure: %s.\n",
6279
+	    fd, xstrerror());
6280
+	if (ignoreErrno(errno)) {
6281
+	    debug(81, 2) ("icapReadReply: FD %d: ignored errno\n", fd);
6282
+	    commSetSelect(fd, COMM_SELECT_READ, icapReadReply, icap, 0);
6283
+	} else if (entry->mem_obj->inmem_hi == 0) {
6284
+	    ErrorState *err;
6285
+	    debug(81, 2) ("icapReadReply: FD %d: generating error page\n", fd);
6286
+	    err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR, (request_t *) request);
6287
+	    err->xerrno = errno;
6288
+	    errorAppendEntry(entry, err);
6289
+	    comm_close(fd);
6290
+	} else {
6291
+	    debug(81, 2) ("icapReadReply: FD %d: just calling comm_close()\n",
6292
+		fd);
6293
+	    comm_close(fd);
6294
+	}
6295
+	return;
6296
+    }
6297
+    if (icapReadReply2(icap) < 0)
6298
+	comm_close(fd);
6299
+}
6300
+
6301
+static int
6302
+icapReadReply2(IcapStateData * icap)
6303
+{
6304
+    size_t done = 0;
6305
+    StoreEntry *entry = icap->respmod.entry;
6306
+    const request_t *request = icap->request;
6307
+    debug(81, 3) ("icapReadReply2\n");
6308
+    if (icap->chunk_buf.size == 0 && entry->mem_obj->inmem_hi == 0) {
6309
+	ErrorState *err;
6310
+	err = errorCon(ERR_ZERO_SIZE_OBJECT, HTTP_SERVICE_UNAVAILABLE, (request_t *) request);
6311
+	err->xerrno = errno;
6312
+	errorAppendEntry(entry, err);
6313
+	icap->flags.http_server_eof = 1;
6314
+	return -1;
6315
+    }
6316
+    if (icap->chunk_buf.size == 0) {
6317
+	/* Retrieval done. */
6318
+	if (icapHttpReplyHdrState(icap) < 2)
6319
+	    icapProcessHttpReplyHeader(icap, icap->chunk_buf.buf,
6320
+		icap->chunk_buf.size);
6321
+	icap->flags.http_server_eof = 1;
6322
+	icapReadReply3(icap);
6323
+	return 0;
6324
+    }
6325
+    if (icapHttpReplyHdrState(icap) == 0) {
6326
+	int expect = icapExpectedHttpReplyHdrSize(icap);
6327
+	int so_far = icap->http_header_bytes_read_so_far;
6328
+	int needed = expect - so_far;
6329
+	debug(81, 3) ("expect=%d\n", expect);
6330
+	debug(81, 3) ("so_far=%d\n", so_far);
6331
+	debug(81, 3) ("needed=%d\n", needed);
6332
+	assert(needed < 0 || needed >= 0);
6333
+	if (0 > expect) {
6334
+	    done = icapProcessHttpReplyHeader(icap,
6335
+		icap->chunk_buf.buf, icap->chunk_buf.size);
6336
+	} else if (0 == expect) {
6337
+	    /*
6338
+	     * this icap reply doesn't give us new HTTP headers
6339
+	     * so we must copy them from our copy
6340
+	     */
6341
+	    debug(81, 1) ("WARNING: untested code at %s:%d\n", __FILE__,
6342
+		__LINE__);
6343
+	    if (icap->respmod.req_hdr_copy.size) {	/*For HTTP 0.9 we do not have headers */
6344
+		storeAppend(entry,
6345
+		    icap->respmod.req_hdr_copy.buf,
6346
+		    icap->respmod.req_hdr_copy.size);
6347
+	    }
6348
+	    done = icapProcessHttpReplyHeader(icap, icap->chunk_buf.buf,
6349
+		icap->chunk_buf.size);
6350
+	    assert(icapHttpReplyHdrState(icap) == 2);
6351
+	    icap->chunk_size = 0;	/*we are ready to read chunks of data now.... */
6352
+	} else if (needed) {
6353
+	    done = icapProcessHttpReplyHeader(icap,
6354
+		icap->chunk_buf.buf, icap->chunk_buf.size);
6355
+	    if (icap->chunk_buf.size >= needed) {
6356
+		/*storeAppend not needed here, appended in httpProcessReplyHeader */
6357
+		/*must done  = so_far - needed */
6358
+		so_far += needed;
6359
+		xmemmove(icap->chunk_buf.buf,
6360
+		    icap->chunk_buf.buf + needed,
6361
+		    icap->chunk_buf.size - needed);
6362
+		icap->chunk_buf.size -= needed;
6363
+		assert(icapHttpReplyHdrState(icap) == 2);
6364
+		icap->chunk_size = 0;
6365
+	    } else {
6366
+		/*
6367
+		 * We don't have the full HTTP reply headers yet, so keep
6368
+		 * the partial reply buffered in 'chunk_buf' and wait
6369
+		 * for more.
6370
+		 */
6371
+		debug(81, 3) ("We don't have full Http headers.Schedule a new read\n");
6372
+		commSetSelect(icap->icap_fd, COMM_SELECT_READ, icapReadReply, icap, 0);
6373
+	    }
6374
+	}
6375
+	icap->http_header_bytes_read_so_far = so_far;
6376
+    }
6377
+    debug(81, 3) ("%s:%d: icap->chunk_buf.size=%d\n", __FILE__, __LINE__,
6378
+	(int) icap->chunk_buf.size);
6379
+    debug(81, 3) ("%s:%d: flags.no_content=%d\n", __FILE__, __LINE__,
6380
+	icap->flags.no_content);
6381
+    if (icap->flags.no_content) {
6382
+	/* data from http.c is not chunked */
6383
+	if (!EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
6384
+	    debug(81, 3) ("copying %d bytes from chunk_buf to entry\n",
6385
+		icap->chunk_buf.size - done);
6386
+	    if ((icap->chunk_buf.size - done) > 0)
6387
+		storeAppend(entry, icap->chunk_buf.buf + done, icap->chunk_buf.size - done);
6388
+	    icap->chunk_buf.size = 0;
6389
+	}
6390
+    } else if (2 == icapHttpReplyHdrState(icap)) {
6391
+	if (icap->chunk_buf.size)
6392
+	    icapParseChunkedBody(icap, (STRCB *) storeAppend, entry);
6393
+    }
6394
+    icapReadReply3(icap);
6395
+    return 0;
6396
+}
6397
+
6398
+static void
6399
+icapReadReply3(IcapStateData * icap)
6400
+{
6401
+    StoreEntry *entry = icap->respmod.entry;
6402
+    int fd = icap->icap_fd;
6403
+    debug(81, 3) ("icapReadReply3\n");
6404
+    if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
6405
+	debug(81, 3) ("icapReadReply3: Entry Aborded\n");
6406
+	if (icap->flags.no_content)
6407
+	    icapStateFree(-1, icap);
6408
+	else
6409
+	    comm_close(fd);
6410
+    } else if (icapPconnTransferDone(fd, icap)) {
6411
+	storeComplete(entry);
6412
+	if (icap->flags.no_content)
6413
+	    icapStateFree(-1, icap);
6414
+	else {
6415
+	    icapRespModKeepAliveOrClose(icap);
6416
+	    icapStateFree(-1, icap);
6417
+	}
6418
+    } else if (!icap->flags.no_content) {
6419
+	/* Wait for EOF condition */
6420
+	commSetSelect(fd, COMM_SELECT_READ, icapReadReply, icap, 0);
6421
+	debug(81,
6422
+	    3)
6423
+	    ("icapReadReply3: Going to read mode data throught icapReadReply\n");
6424
+    } else {
6425
+	debug(81, 3) ("icapReadReply3: Nothing\n");
6426
+    }
6427
+}
6428
Index: src/main.c
6429
===================================================================
6430
RCS file: /cvsroot/squid/squid/src/main.c,v
6431
retrieving revision 1.72
6432
retrieving revision 1.45.4.10
6433
diff -p -u -b -r1.72 -r1.45.4.10
6434
--- src/main.c	23 Oct 2006 11:52:55 -0000	1.72
6435
+++ src/main.c	3 Nov 2006 18:47:14 -0000	1.45.4.10
6436
@@ -391,6 +391,9 @@ mainReconfigure(void)
6437
 #else
6438
     idnsShutdown();
6439
 #endif
6440
+#ifdef HS_FEAT_ICAP
6441
+    icapClose();
6442
+#endif
6443
     redirectShutdown();
6444
     locationRewriteShutdown();
6445
     authenticateShutdown();
6446
@@ -422,6 +425,9 @@ mainReconfigure(void)
6447
 #endif
6448
     redirectInit();
6449
     locationRewriteInit();
6450
+#ifdef HS_FEAT_ICAP
6451
+    icapInit();
6452
+#endif
6453
     authenticateInit(&Config.authConfig);
6454
     externalAclInit();
6455
 #if USE_WCCP
6456
@@ -573,6 +579,9 @@ mainInitialize(void)
6457
     redirectInit();
6458
     locationRewriteInit();
6459
     errorMapInit();
6460
+#ifdef HS_FEAT_ICAP
6461
+    icapInit();
6462
+#endif
6463
     authenticateInit(&Config.authConfig);
6464
     externalAclInit();
6465
     useragentOpenLog();
6466
Index: src/mem.c
6467
===================================================================
6468
RCS file: /cvsroot/squid/squid/src/mem.c,v
6469
retrieving revision 1.27
6470
retrieving revision 1.24.4.3
6471
diff -p -u -b -r1.27 -r1.24.4.3
6472
--- src/mem.c	20 May 2006 22:50:55 -0000	1.27
6473
+++ src/mem.c	26 May 2006 18:21:32 -0000	1.24.4.3
6474
@@ -353,6 +353,13 @@ memInit(void)
6475
     memDataInit(MEM_TLV, "storeSwapTLV", sizeof(tlv), 0);
6476
     memDataInit(MEM_SWAP_LOG_DATA, "storeSwapLogData", sizeof(storeSwapLogData), 0);
6477
 
6478
+#ifdef HS_FEAT_ICAP
6479
+    memDataInit(MEM_ICAP_OPT_DATA, "IcapOptData", sizeof(IcapOptData), 0);
6480
+    memDataInit(MEM_ICAP_SERVICE_LIST, "icap_service_list", sizeof(icap_service_list), 0);
6481
+    memDataInit(MEM_ICAP_CLASS, "icap_class", sizeof(icap_class), 0);
6482
+    memDataInit(MEM_ICAP_ACCESS, "icap_access", sizeof(icap_access), 0);
6483
+#endif
6484
+
6485
     /* init string pools */
6486
     for (i = 0; i < mem_str_pool_count; i++) {
6487
 	StrPools[i].pool = memPoolCreate(StrPoolsAttrs[i].name, StrPoolsAttrs[i].obj_size);
6488
Index: src/mk-string-arrays.pl
6489
===================================================================
6490
--- src/mk-string-arrays.pl.orig	Fri Jan 19 01:19:26 2007
6491
+++ src/mk-string-arrays.pl	Wed Jan 24 12:31:03 2007
6492
@@ -17,6 +17,7 @@ $pat{'icp_opcode'} = "icp_opcode_str";
6493
 $pat{'swap_log_op'} = "swap_log_op_str";
6494
 $pat{'lookup_t'} = "lookup_t_str";
6495
 $pat{'log_type'} = "log_tags";
6496
+$pat{'icap_service_t'} = "icap_service_type_str";
6497
 
6498
 print "#include \"squid.h\"\n";
6499
 
6500
Index: src/pconn.c
6501
===================================================================
6502
RCS file: /cvsroot/squid/squid/src/pconn.c,v
6503
retrieving revision 1.10
6504
retrieving revision 1.9.4.2
6505
diff -p -u -b -r1.10 -r1.9.4.2
6506
--- src/pconn.c	22 May 2006 22:06:12 -0000	1.10
6507
+++ src/pconn.c	26 May 2006 18:21:32 -0000	1.9.4.2
6508
@@ -46,6 +46,9 @@ struct _pconn {
6509
 #define PCONN_HIST_SZ (1<<16)
6510
 int client_pconn_hist[PCONN_HIST_SZ];
6511
 int server_pconn_hist[PCONN_HIST_SZ];
6512
+#ifdef HS_FEAT_ICAP
6513
+int icap_server_pconn_hist[PCONN_HIST_SZ];
6514
+#endif
6515
 
6516
 static PF pconnRead;
6517
 static PF pconnTimeout;
6518
@@ -169,6 +172,20 @@ pconnHistDump(StoreEntry * e)
6519
 	    continue;
6520
 	storeAppendPrintf(e, "\t%4d  %9d\n", i, server_pconn_hist[i]);
6521
     }
6522
+#ifdef HS_FEAT_ICAP
6523
+    storeAppendPrintf(e,
6524
+	"\n"
6525
+	"ICAP-server persistent connection counts:\n"
6526
+	"\n"
6527
+	"\treq/\n"
6528
+	"\tconn      count\n"
6529
+	"\t----  ---------\n");
6530
+    for (i = 0; i < PCONN_HIST_SZ; i++) {
6531
+	if (icap_server_pconn_hist[i] == 0)
6532
+	    continue;
6533
+	storeAppendPrintf(e, "\t%4d  %9d\n", i, icap_server_pconn_hist[i]);
6534
+    }
6535
+#endif
6536
 }
6537
 
6538
 /* ========== PUBLIC FUNCTIONS ============================================ */
6539
@@ -183,6 +200,9 @@ pconnInit(void)
6540
     for (i = 0; i < PCONN_HIST_SZ; i++) {
6541
 	client_pconn_hist[i] = 0;
6542
 	server_pconn_hist[i] = 0;
6543
+#ifdef HS_FEAT_ICAP
6544
+	icap_server_pconn_hist[i] = 0;
6545
+#endif
6546
     }
6547
     pconn_data_pool = memPoolCreate("pconn_data", sizeof(struct _pconn));
6548
     pconn_fds_pool = memPoolCreate("pconn_fds", PCONN_FDS_SZ * sizeof(int));
6549
@@ -265,11 +285,15 @@ pconnHistCount(int what, int i)
6550
 {
6551
     if (i >= PCONN_HIST_SZ)
6552
 	i = PCONN_HIST_SZ - 1;
6553
-    /* what == 0 for client, 1 for server */
6554
+    /* what == 0 for client, 1 for server, 2 for ICAP server */
6555
     if (what == 0)
6556
 	client_pconn_hist[i]++;
6557
     else if (what == 1)
6558
 	server_pconn_hist[i]++;
6559
+#ifdef HS_FEAT_ICAP
6560
+    else if (what == 2)
6561
+	icap_server_pconn_hist[i]++;
6562
+#endif
6563
     else
6564
 	assert(0);
6565
 }
6566
Index: src/protos.h
6567
===================================================================
6568
RCS file: /cvsroot/squid/squid/src/protos.h,v
6569
retrieving revision 1.135
6570
retrieving revision 1.74.4.13
6571
diff -p -u -b -r1.135 -r1.74.4.13
6572
--- src/protos.h	26 Feb 2007 09:51:32 -0000	1.135
6573
+++ src/protos.h	27 Feb 2007 21:57:36 -0000	1.74.4.13
6574
@@ -303,6 +303,8 @@ extern void whoisStart(FwdState *);
6575
 /* http.c */
6576
 extern int httpCachable(method_t);
6577
 extern void httpStart(FwdState *);
6578
+extern void httpParseReplyHeaders(const char *, http_reply *);
6579
+extern size_t httpProcessReplyHeader(HttpStateData *, const char *, int);
6580
 extern int httpBuildRequestPrefix(request_t * request,
6581
     request_t * orig_request,
6582
     StoreEntry * entry,
6583
@@ -626,6 +628,7 @@ extern void memBufVPrintf(MemBuf * mb, c
6584
 extern FREE *memBufFreeFunc(MemBuf * mb);
6585
 /* puts report on MemBuf _module_ usage into mb */
6586
 extern void memBufReport(MemBuf * mb);
6587
+extern int memBufRead(int fd, MemBuf * mb);
6588
 
6589
 extern char *mime_get_header(const char *mime, const char *header);
6590
 extern char *mime_get_header_field(const char *mime, const char *name, const char *prefix);
6591
@@ -1417,4 +1420,55 @@ void storeLocateVaryDone(VaryData * data
6592
 void storeLocateVary(StoreEntry * e, int offset, const char *vary_data, String accept_encoding, STLVCB * callback, void *cbdata);
6593
 void storeAddVary(const char *url, const char *log_url, const method_t method, const cache_key * key, const char *etag, const char *vary, const char *vary_headers, const char *accept_encoding);
6594
 
6595
+#ifdef HS_FEAT_ICAP
6596
+/*
6597
+ * icap_common.c
6598
+ */
6599
+void icapInit(void);
6600
+void icapClose(void);
6601
+void icapParseEncapsulated(IcapStateData *, const char *, const char *);
6602
+icap_service *icapService(icap_service_t, request_t *);
6603
+int icapConnect(IcapStateData *, CNCB *);
6604
+IcapStateData *icapAllocate(void);
6605
+PF icapStateFree;
6606
+PF icapConnectTimeout;
6607
+PF icapReadTimeout;
6608
+icap_service_t icapServiceToType(const char *);
6609
+const char *icapServiceToStr(const icap_service_t);
6610
+int icapCheckAcl(clientHttpRequest *);
6611
+size_t icapLineLength(const char *, int);
6612
+int icapReadHeader(int, IcapStateData *, int *);
6613
+int icapFindHeader(const char *, const char *, const char **, const char **);
6614
+int icapParseKeepAlive(const IcapStateData *, const char *, const char *);
6615
+void icapSetKeepAlive(IcapStateData * icap, const char *hdrs);
6616
+size_t icapParseChunkedBody(IcapStateData *, STRCB *, void *);
6617
+void icapAddAuthUserHeader(MemBuf *, auth_user_request_t *);
6618
+int icapParseStatusLine(const char *, int, int *, int *, const char **);
6619
+
6620
+/*
6621
+ * icap_respmod.c
6622
+ */
6623
+IcapStateData *icapRespModStart(icap_service_t, request_t *, StoreEntry *, http_state_flags);
6624
+void icapSendRespMod(IcapStateData *, int);
6625
+void icapRespModAddResponceHeaders(IcapStateData *, char *, int);
6626
+void icapRespModAddBodyData(IcapStateData *, char *, int);
6627
+CNCB icapConnectOver;
6628
+
6629
+/*
6630
+ * icap_reqmod.c
6631
+ */
6632
+IcapStateData *icapReqModStart(icap_service*, const char *, request_t *, int, struct timeval, struct in_addr, void *);
6633
+
6634
+/* icap_opt.c */
6635
+void icapOptInit(void);
6636
+void icapOptShutdown(void);
6637
+void icapOptSetUnreachable(icap_service * s);
6638
+
6639
+/* X-Server-IP support */
6640
+void icapAddOriginIP(MemBuf *, const char *);
6641
+
6642
+/* for debugging purposes only */
6643
+void dump_icap_config(IcapConfig * cfg);
6644
+#endif
6645
+
6646
 #endif /* SQUID_PROTOS_H */
6647
Index: src/squid.h
6648
===================================================================
6649
RCS file: /cvsroot/squid/squid/src/squid.h,v
6650
retrieving revision 1.36
6651
retrieving revision 1.24.8.7
6652
diff -p -u -b -r1.36 -r1.24.8.7
6653
--- src/squid.h	8 Sep 2006 19:50:59 -0000	1.36
6654
+++ src/squid.h	26 Sep 2006 22:47:38 -0000	1.24.8.7
6655
@@ -38,6 +38,14 @@
6656
 #include "config.h"
6657
 
6658
 /*
6659
+ * experimental defines for ICAP
6660
+ */
6661
+#ifdef HS_FEAT_ICAP
6662
+#define ICAP_PREVIEW 1
6663
+#define SUPPORT_ICAP_204 0
6664
+#endif
6665
+
6666
+/*
6667
  * On some systems, FD_SETSIZE is set to something lower than the
6668
  * actual number of files which can be opened.  IRIX is one case,
6669
  * NetBSD is another.  So here we increase FD_SETSIZE to our
6670
Index: src/stat.c
6671
===================================================================
6672
RCS file: /cvsroot/squid/squid/src/stat.c,v
6673
retrieving revision 1.38
6674
retrieving revision 1.26.8.10
6675
diff -p -u -b -r1.38 -r1.26.8.10
6676
--- src/stat.c	1 Nov 2006 21:51:29 -0000	1.38
6677
+++ src/stat.c	3 Nov 2006 18:47:14 -0000	1.26.8.10
6678
@@ -804,6 +804,17 @@ statAvgDump(StoreEntry * sentry, int min
6679
     storeAppendPrintf(sentry, "server.other.kbytes_out = %f/sec\n",
6680
 	XAVG(server.other.kbytes_out.kb));
6681
 
6682
+#ifdef HS_FEAT_ICAP
6683
+    storeAppendPrintf(sentry, "icap.all.requests = %f/sec\n",
6684
+	XAVG(icap.all.requests));
6685
+    storeAppendPrintf(sentry, "icap.all.errors = %f/sec\n",
6686
+	XAVG(icap.all.errors));
6687
+    storeAppendPrintf(sentry, "icap.all.kbytes_in = %f/sec\n",
6688
+	XAVG(icap.all.kbytes_in.kb));
6689
+    storeAppendPrintf(sentry, "icap.all.kbytes_out = %f/sec\n",
6690
+	XAVG(icap.all.kbytes_out.kb));
6691
+#endif
6692
+
6693
     storeAppendPrintf(sentry, "icp.pkts_sent = %f/sec\n",
6694
 	XAVG(icp.pkts_sent));
6695
     storeAppendPrintf(sentry, "icp.pkts_recv = %f/sec\n",
6696
@@ -1188,6 +1199,17 @@ statCountersDump(StoreEntry * sentry)
6697
     storeAppendPrintf(sentry, "server.other.kbytes_out = %d\n",
6698
 	(int) f->server.other.kbytes_out.kb);
6699
 
6700
+#if HS_FEAT_ICAP
6701
+    storeAppendPrintf(sentry, "icap.all.requests = %d\n",
6702
+	(int) f->icap.all.requests);
6703
+    storeAppendPrintf(sentry, "icap.all.errors = %d\n",
6704
+	(int) f->icap.all.errors);
6705
+    storeAppendPrintf(sentry, "icap.all.kbytes_in = %d\n",
6706
+	(int) f->icap.all.kbytes_in.kb);
6707
+    storeAppendPrintf(sentry, "icap.all.kbytes_out = %d\n",
6708
+	(int) f->icap.all.kbytes_out.kb);
6709
+#endif
6710
+
6711
     storeAppendPrintf(sentry, "icp.pkts_sent = %d\n",
6712
 	f->icp.pkts_sent);
6713
     storeAppendPrintf(sentry, "icp.pkts_recv = %d\n",
6714
@@ -1488,8 +1510,6 @@ statClientRequests(StoreEntry * s)
6715
 	    storeAppendPrintf(s, "\tme: %s:%d\n",
6716
 		inet_ntoa(conn->me.sin_addr),
6717
 		ntohs(conn->me.sin_port));
6718
-	    storeAppendPrintf(s, "\tnrequests: %d\n",
6719
-		conn->nrequests);
6720
 	    storeAppendPrintf(s, "\tdefer: n %d, until %ld\n",
6721
 		conn->defer.n, (long int) conn->defer.until);
6722
 	}
6723
Index: src/store.c
6724
===================================================================
6725
RCS file: /cvsroot/squid/squid/src/store.c,v
6726
retrieving revision 1.39
6727
retrieving revision 1.21.10.10
6728
diff -p -u -b -r1.39 -r1.21.10.10
6729
--- src/store.c	10 Dec 2006 06:51:20 -0000	1.39
6730
+++ src/store.c	12 Dec 2006 22:49:46 -0000	1.21.10.10
6731
@@ -1105,8 +1105,17 @@ storeAppend(StoreEntry * e, const char *
6732
     MemObject *mem = e->mem_obj;
6733
     assert(mem != NULL);
6734
     assert(len >= 0);
6735
-    assert(e->store_status == STORE_PENDING);
6736
     mem->refresh_timestamp = squid_curtime;
6737
+    debug(20, 3) ("storeAppend: '%s'\n", storeKeyText(e->hash.key));
6738
+    if (e->store_status != STORE_PENDING) {
6739
+	/*
6740
+	 * if we're not STORE_PENDING, then probably we got aborted
6741
+	 * and there should be NO clients on this entry
6742
+	 */
6743
+	assert(EBIT_TEST(e->flags, ENTRY_ABORTED));
6744
+	assert(e->mem_obj->nclients == 0);
6745
+	return;
6746
+    }
6747
     if (len) {
6748
 	debug(20, 5) ("storeAppend: appending %d bytes for '%s'\n",
6749
 	    len,
6750
Index: src/structs.h
6751
===================================================================
6752
RCS file: /cvsroot/squid/squid/src/structs.h,v
6753
retrieving revision 1.141
6754
retrieving revision 1.81.4.14
6755
diff -p -u -b -r1.141 -r1.81.4.14
6756
--- src/structs.h	27 Feb 2007 01:16:38 -0000	1.141
6757
+++ src/structs.h	27 Feb 2007 21:57:44 -0000	1.81.4.14
6758
@@ -423,6 +423,23 @@ struct _RemovalPolicySettings {
6759
     wordlist *args;
6760
 };
6761
 
6762
+#if HS_FEAT_ICAP
6763
+struct _IcapConfig {
6764
+    int onoff;
6765
+    int preview_enable;
6766
+    icap_service *service_head;
6767
+    icap_class *class_head;
6768
+    icap_access *access_head;
6769
+    int preview_size;
6770
+    int check_interval;
6771
+    int send_client_ip;
6772
+    int send_server_ip;
6773
+    int send_auth_user;
6774
+    char *auth_scheme;
6775
+};
6776
+
6777
+#endif /* HS_FEAT_ICAP */
6778
+
6779
 struct _SquidConfig {
6780
     struct {
6781
 	squid_off_t maxSize;
6782
@@ -805,6 +822,9 @@ struct _SquidConfig {
6783
 #endif
6784
     time_t refresh_stale_window;
6785
     int umask;
6786
+#ifdef HS_FEAT_ICAP
6787
+    IcapConfig icapcfg;
6788
+#endif
6789
 };
6790
 
6791
 struct _SquidConfig2 {
6792
@@ -887,6 +907,10 @@ struct _fde {
6793
     comm_pending write_pending;
6794
     squid_off_t bytes_read;
6795
     squid_off_t bytes_written;
6796
+    struct {
6797
+	int uses;
6798
+	int type;
6799
+    } pconn;
6800
     int uses;			/* ie # req's over persistent conn */
6801
     struct _fde_disk {
6802
 	DWCB *wrt_handle;
6803
@@ -1094,6 +1118,131 @@ struct _http_state_flags {
6804
     unsigned int trailer:1;
6805
 };
6806
 
6807
+#ifdef HS_FEAT_ICAP
6808
+struct _IcapStateData {
6809
+    request_t *request;
6810
+    http_state_flags http_flags;
6811
+    HttpStateData *httpState;	/* needed to parse HTTP headers only */
6812
+    int icap_fd;
6813
+    int sc;
6814
+    icap_service *current_service;
6815
+    MemBuf icap_hdr;
6816
+    struct {
6817
+	int res_hdr;
6818
+	int res_body;
6819
+	int req_hdr;
6820
+	int req_body;
6821
+	int opt_body;
6822
+	int null_body;
6823
+    } enc;
6824
+    int bytes_to_gobble;
6825
+    int chunk_size;
6826
+    MemBuf chunk_buf;
6827
+    int preview_size;
6828
+    squid_off_t fake_content_length;
6829
+    int http_header_bytes_read_so_far;
6830
+    struct {
6831
+	const char *uri;	/* URI for REQMODs */
6832
+	int client_fd;
6833
+	struct timeval start;	/* for logging */
6834
+	struct in_addr log_addr;	/* for logging */
6835
+	int hdr_state;
6836
+	MemBuf hdr_buf;
6837
+	void *client_cookie;
6838
+	struct {
6839
+	    MemBuf buf;
6840
+	    CBCB *callback;
6841
+	    void *callback_data;
6842
+	    char *callback_buf;
6843
+	    size_t callback_bufsize;
6844
+	    squid_off_t bytes_read;
6845
+	} http_entity;
6846
+    } reqmod;
6847
+    struct {
6848
+	StoreEntry *entry;
6849
+	MemBuf buffer;
6850
+	MemBuf req_hdr_copy;	/* XXX barf */
6851
+	MemBuf resp_copy;	/* XXX barf^max */
6852
+	squid_off_t res_body_sz;
6853
+    } respmod;
6854
+    struct {
6855
+	unsigned int connect_requested:1;
6856
+	unsigned int connect_pending:1;
6857
+	unsigned int write_pending:1;
6858
+	unsigned int keep_alive:1;
6859
+	unsigned int http_server_eof:1;
6860
+	unsigned int send_zero_chunk:1;
6861
+	unsigned int got_reply:1;
6862
+	unsigned int wait_for_reply:1;
6863
+	unsigned int wait_for_preview_reply:1;
6864
+	unsigned int preview_done:1;
6865
+	unsigned int copy_response:1;
6866
+	unsigned int no_content:1;
6867
+	unsigned int reqmod_http_entity_eof:1;
6868
+    } flags;
6869
+};
6870
+
6871
+struct _icap_service {
6872
+    icap_service *next;
6873
+    char *name;			/* name to be used when referencing ths service */
6874
+    char *uri;			/* uri of server/service to use */
6875
+    char *type_name;		/* {req|resp}mod_{pre|post}cache */
6876
+
6877
+    char *hostname;
6878
+    unsigned short int port;
6879
+    char *resource;
6880
+    icap_service_t type;	/* parsed type */
6881
+    icap_method_t method;
6882
+    ushort bypass;		/* flag: bypass allowed */
6883
+    ushort unreachable;		/* flag: set to 1 if options request fails */
6884
+    IcapOptData *opt;		/* temp data needed during opt request */
6885
+    struct {
6886
+	unsigned int allow_204:1;
6887
+	unsigned int need_x_client_ip:1;
6888
+	unsigned int need_x_server_ip:1;
6889
+	unsigned int need_x_authenticated_user:1;
6890
+    } flags;
6891
+    int preview;
6892
+    String istag;
6893
+    String transfer_preview;
6894
+    String transfer_ignore;
6895
+    String transfer_complete;
6896
+    int max_connections;
6897
+    int options_ttl;
6898
+    int keep_alive;
6899
+};
6900
+
6901
+struct _icap_service_list {
6902
+    icap_service_list *next;
6903
+    icap_service *services[16];
6904
+    int nservices;		/* Number of services already used */
6905
+    int last_service_used;	/* Last services used, use to do a round robin */
6906
+};
6907
+
6908
+struct _icap_class {
6909
+    icap_class *next;
6910
+    char *name;
6911
+    wordlist *services;
6912
+    icap_service_list *isl;
6913
+    ushort hidden;		/* for unnamed classes */
6914
+};
6915
+
6916
+struct _icap_access {
6917
+    icap_access *next;
6918
+    char *service_name;
6919
+    icap_class *class;
6920
+    acl_access *access;
6921
+};
6922
+
6923
+struct _IcapOptData {
6924
+    char *buf;
6925
+    off_t offset;
6926
+    size_t size;
6927
+    off_t headlen;
6928
+};
6929
+
6930
+#endif
6931
+
6932
 struct _HttpStateData {
6933
     StoreEntry *entry;
6934
     request_t *request;
6935
@@ -1105,12 +1254,16 @@ struct _HttpStateData {
6936
     int fd;
6937
     http_state_flags flags;
6938
     FwdState *fwd;
6939
+#ifdef HS_FEAT_ICAP
6940
+    struct _IcapStateData *icap_writer;
6941
+#endif
6942
     char *body_buf;
6943
     int body_buf_sz;
6944
     squid_off_t chunk_size;
6945
     String chunkhdr;
6946
 };
6947
 
6948
+
6949
 struct _icpUdpData {
6950
     struct sockaddr_in address;
6951
     void *msg;
6952
@@ -1219,6 +1372,7 @@ struct _clientHttpRequest {
6953
 	unsigned int internal:1;
6954
 	unsigned int done_copying:1;
6955
 	unsigned int purging:1;
6956
+	unsigned int did_icap_reqmod:1;
6957
 	unsigned int hit:1;
6958
     } flags;
6959
     struct {
6960
@@ -1233,6 +1387,9 @@ struct _clientHttpRequest {
6961
      * zero.. [ahc]
6962
      */
6963
     char readbuf[CLIENT_SOCK_SZ];
6964
+#if HS_FEAT_ICAP
6965
+    IcapStateData *icap_reqmod;
6966
+#endif
6967
 };
6968
 
6969
 struct _ConnStateData {
6970
@@ -1901,6 +2058,9 @@ struct _request_t {
6971
     unsigned int done_etag:1;	/* We have done clientProcessETag on this, don't attempt it again */
6972
     char *urlgroup;		/* urlgroup, returned by redirectors */
6973
     char *peer_domain;		/* Configured peer forceddomain */
6974
+#if HS_FEAT_ICAP
6975
+    icap_class *class;
6976
+#endif
6977
     BODY_HANDLER *body_reader;
6978
     void *body_reader_data;
6979
     String extacl_log;		/* String to be used for access.log purposes */
6980
@@ -2008,7 +2168,11 @@ struct _StatCounters {
6981
 	    kb_t kbytes_in;
6982
 	    kb_t kbytes_out;
6983
 	} all , http, ftp, other;
6984
-    } server;
6985
+    }
6986
+#if HS_FEAT_ICAP
6987
+	icap,
6988
+#endif
6989
+	server;
6990
     struct {
6991
 	int pkts_sent;
6992
 	int queries_sent;
6993
Index: src/typedefs.h
6994
===================================================================
6995
RCS file: /cvsroot/squid/squid/src/typedefs.h,v
6996
retrieving revision 1.41
6997
retrieving revision 1.32.4.8
6998
diff -p -u -b -r1.41 -r1.32.4.8
6999
--- src/typedefs.h	2 Sep 2006 14:17:45 -0000	1.41
7000
+++ src/typedefs.h	26 Sep 2006 22:47:39 -0000	1.32.4.8
7001
@@ -136,6 +136,15 @@ typedef struct _HttpHeaderStat HttpHeade
7002
 typedef struct _HttpBody HttpBody;
7003
 typedef struct _HttpReply HttpReply;
7004
 typedef struct _HttpStateData HttpStateData;
7005
+#ifdef HS_FEAT_ICAP
7006
+typedef struct _IcapStateData IcapStateData;
7007
+typedef struct _IcapConfig IcapConfig;
7008
+typedef struct _icap_service icap_service;
7009
+typedef struct _icap_service_list icap_service_list;
7010
+typedef struct _icap_class icap_class;
7011
+typedef struct _icap_access icap_access;
7012
+typedef struct _IcapOptData IcapOptData;
7013
+#endif
7014
 typedef struct _icpUdpData icpUdpData;
7015
 typedef struct _clientHttpRequest clientHttpRequest;
7016
 typedef struct _ConnStateData ConnStateData;
7017
Index: src/url.c
7018
===================================================================
7019
RCS file: /cvsroot/squid/squid/src/url.c,v
7020
retrieving revision 1.17
7021
retrieving revision 1.14.10.4
7022
diff -p -u -b -r1.17 -r1.14.10.4
7023
--- src/url.c	17 Jun 2006 23:51:19 -0000	1.17
7024
+++ src/url.c	28 Jun 2006 21:12:01 -0000	1.14.10.4
7025
@@ -103,6 +103,9 @@ const char *ProtocolStr[] =
7026
     "whois",
7027
     "internal",
7028
     "https",
7029
+#ifdef HS_FEAT_ICAP
7030
+    "icap",
7031
+#endif
7032
     "TOTAL"
7033
 };
7034
 
7035
@@ -217,6 +220,10 @@ urlParseProtocol(const char *s)
7036
 	return PROTO_WHOIS;
7037
     if (strcasecmp(s, "internal") == 0)
7038
 	return PROTO_INTERNAL;
7039
+#ifdef HS_FEAT_ICAP
7040
+    if (strcasecmp(s, "icap") == 0)
7041
+	return PROTO_ICAP;
7042
+#endif
7043
     return PROTO_NONE;
7044
 }
7045
 
7046
@@ -240,6 +247,10 @@ urlDefaultPort(protocol_t p)
7047
 	return CACHE_HTTP_PORT;
7048
     case PROTO_WHOIS:
7049
 	return 43;
7050
+#ifdef HS_FEAT_ICAP
7051
+    case PROTO_ICAP:
7052
+	return 1344;
7053
+#endif
7054
     default:
7055
 	return 0;
7056
     }
(-)files/icap-2.6-bootstrap.patch (-340 lines)
Lines 1-479 Link Here
1
Patch 2 of 2 to integrate the icap-2_6 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.6-core.patch for further information.
9
10
Patch last updated: 2007-05-17
11
12
--- configure.orig	Thu May 17 13:34:14 2007
13
+++ configure	Thu May 17 13:35:15 2007
14
@@ -312,7 +312,7 @@
15
 # include <unistd.h>
16
 #endif"
17
 
18
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE build build_cpu build_vendor build_os host host_cpu host_vendor host_os PKGCONFIG CGIEXT ENABLE_WIN32SPECIFIC_TRUE ENABLE_WIN32SPECIFIC_FALSE ENABLE_MINGW32SPECIFIC_TRUE ENABLE_MINGW32SPECIFIC_FALSE WI
19
N32_PSAPI CACHE_HTTP_PORT CACHE_ICP_PORT LIBDLMALLOC LIB_MALLOC STORE_OBJS STORE_LIBS STORE_MODULES NEED_DISKD_TRUE NEED_DISKD_FALSE USE_AIOPS_WIN32_TRUE USE_AIOPS_WIN32_FALSE NEED_COSSDUMP_TRUE NEED_COSSDUMP_FALSE REPL_POLICIES REPL_OBJS REPL_LIBS ENABLE_PINGER_TRUE ENABLE_PINGER_FALSE USE_DELAY_POOLS_TRUE USE_DELAY_POOLS_FALSE USE_SNMP_TRUE USE_SNMP_FALSE SNMPLIB makesnmplib ENABLE_HTCP_TRUE ENABLE_HTCP_FALSE ENABLE_SSL_TRUE ENABLE_SSL_FALSE NEED_OWN_MD5_TRUE NEED_OWN_MD5_FALSE SSLLIB ERR_DEFAULT_LANGUAGE ERR_LANGUAGES MAKE_LEAKFINDER_TRUE MAKE_LEAKFINDER_FALSE USE_DNSSERVER_TRUE USE_DNSSERVER_FALSE OPT_DEFAULT_HOSTS AUTH_MODULES AUTH_OBJS AUTH_LIBS BASIC_AUTH_HELPERS NTLM_AUTH_HELPERS DIGEST_AUTH_HELPERS NEGOTIATE_AUTH_HELPERS EXTERNAL_ACL_HELPERS CPP EGREP LIBSASL ENABLE_UNLINKD_TRUE ENABLE_UNLINKD_FALSE RANLIB ac_ct_RANLIB LN_S SH FALSE TRUE RM MV MKDIR LN PERL AR AR_R ALLOCA CRYPTLIB LIB_EPOLL LIB_LDAP LIB_LBER LIB_DB USE_POLL_TRUE USE_POLL_FALSE USE_EPOLL_TRUE USE_EPO
0
N32_PSAPI CACHE_HTTP_PORT CACHE_ICP_PORT LIBDLMALLOC LIB_MALLOC STORE_OBJS STORE_LIBS STORE_MODULES NEED_DISKD_TRUE NEED_DISKD_FALSE USE_AIOPS_WIN32_TRUE USE_AIOPS_WIN32_FALSE NEED_COSSDUMP_TRUE NEED_COSSDUMP_FALSE REPL_POLICIES REPL_OBJS REPL_LIBS ENABLE_PINGER_TRUE ENABLE_PINGER_FALSE USE_DELAY_POOLS_TRUE USE_DELAY_POOLS_FALSE USE_SNMP_TRUE USE_SNMP_FALSE SNMPLIB makesnmplib ENABLE_HTCP_TRUE ENABLE_HTCP_FALSE ENABLE_SSL_TRUE ENABLE_SSL_FALSE NEED_OWN_MD5_TRUE NEED_OWN_MD5_FALSE SSLLIB ERR_DEFAULT_LANGUAGE ERR_LANGUAGES MAKE_LEAKFINDER_TRUE MAKE_LEAKFINDER_FALSE USE_DNSSERVER_TRUE USE_DNSSERVER_FALSE OPT_DEFAULT_HOSTS AUTH_MODULES AUTH_OBJS AUTH_LIBS BASIC_AUTH_HELPERS NTLM_AUTH_HELPERS DIGEST_AUTH_HELPERS NEGOTIATE_AUTH_HELPERS EXTERNAL_ACL_HELPERS CPP EGREP LIBSASL ENABLE_UNLINKD_TRUE ENABLE_UNLINKD_FALSE RANLIB ac_ct_RANLIB LN_S SH FALSE TRUE RM MV MKDIR LN PERL AR AR_R ALLOCA CRYPTLIB LIB_EPOLL LIB_LDAP LIB_LBER LIB_DB USE_POLL_TRUE USE_POLL_FALSE USE_EPOLL_TRUE USE_EPO
20
LL_FALSE USE_SELECT_TRUE USE_SELECT_FALSE USE_SELECT_SIMPLE_!
1
LL_FALSE USE_SELECT_TRUE USE_SELECT_FALSE USE_SELECT_SIMPLE_!
21
TRUE USE
2
TRUE USE
22
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE build build_cpu build_vendor build_os host host_cpu host_vendor host_os PKGCONFIG CGIEXT ENABLE_WIN32SPECIFIC_TRUE ENABLE_WIN32SPECIFIC_FALSE ENABLE_MINGW32SPECIFIC_TRUE ENABLE_MINGW32SPECIFIC_FALSE WI
23
N32_PSAPI CACHE_HTTP_PORT CACHE_ICP_PORT LIBDLMALLOC LIB_MALLOC STORE_OBJS STORE_LIBS STORE_MODULES NEED_DISKD_TRUE NEED_DISKD_FALSE USE_AIOPS_WIN32_TRUE USE_AIOPS_WIN32_FALSE NEED_COSSDUMP_TRUE NEED_COSSDUMP_FALSE REPL_POLICIES REPL_OBJS REPL_LIBS ENABLE_PINGER_TRUE ENABLE_PINGER_FALSE USE_DELAY_POOLS_TRUE USE_DELAY_POOLS_FALSE USE_ICAP_TRUE USE_ICAP_FALSE USE_SNMP_TRUE USE_SNMP_FALSE SNMPLIB makesnmplib ENABLE_HTCP_TRUE ENABLE_HTCP_FALSE ENABLE_SSL_TRUE ENABLE_SSL_FALSE NEED_OWN_MD5_TRUE NEED_OWN_MD5_FALSE SSLLIB ERR_DEFAULT_LANGUAGE ERR_LANGUAGES MAKE_LEAKFINDER_TRUE MAKE_LEAKFINDER_FALSE USE_DNSSERVER_TRUE USE_DNSSERVER_FALSE OPT_DEFAULT_HOSTS AUTH_MODULES AUTH_OBJS AUTH_LIBS BASIC_AUTH_HELPERS NTLM_AUTH_HELPERS DIGEST_AUTH_HELPERS NEGOTIATE_AUTH_HELPERS EXTERNAL_ACL_HELPERS CPP EGREP LIBSASL ENABLE_UNLINKD_TRUE ENABLE_UNLINKD_FALSE RANLIB ac_ct_RANLIB LN_S SH FALSE TRUE RM MV MKDIR LN PERL AR AR_R ALLOCA CRYPTLIB LIB_EPOLL LIB_LDAP LIB_LBER LIB_DB USE_POLL_TRUE USE_POLL
3
N32_PSAPI CACHE_HTTP_PORT CACHE_ICP_PORT LIBDLMALLOC LIB_MALLOC STORE_OBJS STORE_LIBS STORE_MODULES NEED_DISKD_TRUE NEED_DISKD_FALSE USE_AIOPS_WIN32_TRUE USE_AIOPS_WIN32_FALSE NEED_COSSDUMP_TRUE NEED_COSSDUMP_FALSE REPL_POLICIES REPL_OBJS REPL_LIBS ENABLE_PINGER_TRUE ENABLE_PINGER_FALSE USE_DELAY_POOLS_TRUE USE_DELAY_POOLS_FALSE USE_ICAP_TRUE USE_ICAP_FALSE USE_SNMP_TRUE USE_SNMP_FALSE SNMPLIB makesnmplib ENABLE_HTCP_TRUE ENABLE_HTCP_FALSE ENABLE_SSL_TRUE ENABLE_SSL_FALSE NEED_OWN_MD5_TRUE NEED_OWN_MD5_FALSE SSLLIB ERR_DEFAULT_LANGUAGE ERR_LANGUAGES MAKE_LEAKFINDER_TRUE MAKE_LEAKFINDER_FALSE USE_DNSSERVER_TRUE USE_DNSSERVER_FALSE OPT_DEFAULT_HOSTS AUTH_MODULES AUTH_OBJS AUTH_LIBS BASIC_AUTH_HELPERS NTLM_AUTH_HELPERS DIGEST_AUTH_HELPERS NEGOTIATE_AUTH_HELPERS EXTERNAL_ACL_HELPERS CPP EGREP LIBSASL ENABLE_UNLINKD_TRUE ENABLE_UNLINKD_FALSE RANLIB ac_ct_RANLIB LN_S SH FALSE TRUE RM MV MKDIR LN PERL AR AR_R ALLOCA CRYPTLIB LIB_EPOLL LIB_LDAP LIB_LBER LIB_DB USE_POLL_TRUE USE_POLL
24
_FALSE USE_EPOLL_TRUE USE_EPOLL_FALSE USE_SELECT_TRUE USE_SE!
4
_FALSE USE_EPOLL_TRUE USE_EPOLL_FALSE USE_SELECT_TRUE USE_SE!
25
LECT_FAL
5
LECT_FAL
26
 ac_subst_files=''
27
 
28
 # Initialize some variables set by options.
29
@@ -890,6 +890,7 @@
30
 			  to build your custom policy
31
   --enable-icmp           Enable ICMP pinging
32
   --enable-delay-pools    Enable delay pools to limit bandwidth usage
33
+  --enable-icap-support   	   Enable ICAP client capability
34
   --enable-useragent-log  Enable logging of User-Agent header
35
   --enable-referer-log    Enable logging of Referer header
36
   --disable-wccp          Disable Web Cache Coordination V1 Protocol
37
@@ -1818,7 +1818,7 @@
38
 
39
 # Define the identity of the package.
40
  PACKAGE='squid'
41
- VERSION='2.6.STABLE13'
42
+ VERSION='2.6.STABLE13+ICAP'
43
 
44
 
45
 cat >>confdefs.h <<_ACEOF
46
@@ -3954,6 +3955,40 @@
47
 fi;
48
 
49
 
50
+
51
+if false; then
52
+  USE_ICAP_TRUE=
53
+  USE_ICAP_FALSE='#'
54
+else
55
+  USE_ICAP_TRUE='#'
56
+  USE_ICAP_FALSE=
57
+fi
58
+
59
+# Check whether --enable-icap-support or --disable-icap-support was given.
60
+if test "${enable_icap_support+set}" = set; then
61
+  enableval="$enable_icap_support"
62
+   if test "$enableval" = "yes" ; then
63
+    echo "ICAP support enabled"
64
+
65
+cat >>confdefs.h <<\_ACEOF
66
+#define HS_FEAT_ICAP 1
67
+_ACEOF
68
+
69
+
70
+
71
+if true; then
72
+  USE_ICAP_TRUE=
73
+  USE_ICAP_FALSE='#'
74
+else
75
+  USE_ICAP_TRUE='#'
76
+  USE_ICAP_FALSE=
77
+fi
78
+
79
+  fi
80
+
81
+fi;
82
+
83
+
84
 # Check whether --enable-useragent-log or --disable-useragent-log was given.
85
 if test "${enable_useragent_log+set}" = set; then
86
   enableval="$enable_useragent_log"
87
@@ -15923,6 +15958,8 @@
88
 
89
 
90
 
91
+
92
+
93
 for ac_func in \
94
 	bcopy \
95
 	backtrace_symbols_fd \
96
@@ -15971,6 +16008,8 @@
97
 	srand48 \
98
 	srandom \
99
 	statfs \
100
+	strnstr \
101
+	strcasestr \
102
 	strsep \
103
 	strtoll \
104
 	sysconf \
105
@@ -16430,6 +16469,52 @@
106
 
107
 
108
 if false; then
109
+  NEED_OWN_STRNSTR_TRUE=
110
+  NEED_OWN_STRNSTR_FALSE='#'
111
+else
112
+  NEED_OWN_STRNSTR_TRUE='#'
113
+  NEED_OWN_STRNSTR_FALSE=
114
+fi
115
+
116
+if test "$ac_cv_func_strnstr" = "no" || test "$ac_cv_func_vstrnstr" = "no" ; then
117
+
118
+
119
+if true; then
120
+  NEED_OWN_STRNSTR_TRUE=
121
+  NEED_OWN_STRNSTR_FALSE='#'
122
+else
123
+  NEED_OWN_STRNSTR_TRUE='#'
124
+  NEED_OWN_STRNSTR_FALSE=
125
+fi
126
+
127
+fi
128
+
129
+
130
+
131
+if false; then
132
+  NEED_OWN_STRCASESTR_TRUE=
133
+  NEED_OWN_STRCASESTR_FALSE='#'
134
+else
135
+  NEED_OWN_STRCASESTR_TRUE='#'
136
+  NEED_OWN_STRCASESTR_FALSE=
137
+fi
138
+
139
+if test "$ac_cv_func_strcasestr" = "no" || test "$ac_cv_func_vstrcasestr" = "no"; then
140
+
141
+
142
+if true; then
143
+  NEED_OWN_STRCASESTR_TRUE=
144
+  NEED_OWN_STRCASESTR_FALSE='#'
145
+else
146
+  NEED_OWN_STRCASESTR_TRUE='#'
147
+  NEED_OWN_STRCASESTR_FALSE=
148
+fi
149
+
150
+fi
151
+
152
+
153
+
154
+if false; then
155
   NEED_OWN_STRSEP_TRUE=
156
   NEED_OWN_STRSEP_FALSE='#'
157
 else
158
@@ -17947,6 +18032,20 @@
159
 Usually this means the macro was only invoked conditionally." >&2;}
160
    { (exit 1); exit 1; }; }
161
 fi
162
+if test -z "${USE_ICAP_TRUE}" && test -z "${USE_ICAP_FALSE}"; then
163
+  { { echo "$as_me:$LINENO: error: conditional \"USE_ICAP\" was never defined.
164
+Usually this means the macro was only invoked conditionally." >&5
165
+echo "$as_me: error: conditional \"USE_ICAP\" was never defined.
166
+Usually this means the macro was only invoked conditionally." >&2;}
167
+   { (exit 1); exit 1; }; }
168
+fi
169
+if test -z "${USE_ICAP_TRUE}" && test -z "${USE_ICAP_FALSE}"; then
170
+  { { echo "$as_me:$LINENO: error: conditional \"USE_ICAP\" was never defined.
171
+Usually this means the macro was only invoked conditionally." >&5
172
+echo "$as_me: error: conditional \"USE_ICAP\" was never defined.
173
+Usually this means the macro was only invoked conditionally." >&2;}
174
+   { (exit 1); exit 1; }; }
175
+fi
176
 if test -z "${USE_SNMP_TRUE}" && test -z "${USE_SNMP_FALSE}"; then
177
   { { echo "$as_me:$LINENO: error: conditional \"USE_SNMP\" was never defined.
178
 Usually this means the macro was only invoked conditionally." >&5
179
@@ -18101,6 +18200,34 @@
180
 Usually this means the macro was only invoked conditionally." >&2;}
181
    { (exit 1); exit 1; }; }
182
 fi
183
+if test -z "${NEED_OWN_STRNSTR_TRUE}" && test -z "${NEED_OWN_STRNSTR_FALSE}"; then
184
+  { { echo "$as_me:$LINENO: error: conditional \"NEED_OWN_STRNSTR\" was never defined.
185
+Usually this means the macro was only invoked conditionally." >&5
186
+echo "$as_me: error: conditional \"NEED_OWN_STRNSTR\" was never defined.
187
+Usually this means the macro was only invoked conditionally." >&2;}
188
+   { (exit 1); exit 1; }; }
189
+fi
190
+if test -z "${NEED_OWN_STRNSTR_TRUE}" && test -z "${NEED_OWN_STRNSTR_FALSE}"; then
191
+  { { echo "$as_me:$LINENO: error: conditional \"NEED_OWN_STRNSTR\" was never defined.
192
+Usually this means the macro was only invoked conditionally." >&5
193
+echo "$as_me: error: conditional \"NEED_OWN_STRNSTR\" was never defined.
194
+Usually this means the macro was only invoked conditionally." >&2;}
195
+   { (exit 1); exit 1; }; }
196
+fi
197
+if test -z "${NEED_OWN_STRCASESTR_TRUE}" && test -z "${NEED_OWN_STRCASESTR_FALSE}"; then
198
+  { { echo "$as_me:$LINENO: error: conditional \"NEED_OWN_STRCASESTR\" was never defined.
199
+Usually this means the macro was only invoked conditionally." >&5
200
+echo "$as_me: error: conditional \"NEED_OWN_STRCASESTR\" was never defined.
201
+Usually this means the macro was only invoked conditionally." >&2;}
202
+   { (exit 1); exit 1; }; }
203
+fi
204
+if test -z "${NEED_OWN_STRCASESTR_TRUE}" && test -z "${NEED_OWN_STRCASESTR_FALSE}"; then
205
+  { { echo "$as_me:$LINENO: error: conditional \"NEED_OWN_STRCASESTR\" was never defined.
206
+Usually this means the macro was only invoked conditionally." >&5
207
+echo "$as_me: error: conditional \"NEED_OWN_STRCASESTR\" was never defined.
208
+Usually this means the macro was only invoked conditionally." >&2;}
209
+   { (exit 1); exit 1; }; }
210
+fi
211
 if test -z "${NEED_OWN_STRSEP_TRUE}" && test -z "${NEED_OWN_STRSEP_FALSE}"; then
212
   { { echo "$as_me:$LINENO: error: conditional \"NEED_OWN_STRSEP\" was never defined.
213
 Usually this means the macro was only invoked conditionally." >&5
214
@@ -18766,6 +18893,8 @@
215
 s,@ENABLE_PINGER_FALSE@,$ENABLE_PINGER_FALSE,;t t
216
 s,@USE_DELAY_POOLS_TRUE@,$USE_DELAY_POOLS_TRUE,;t t
217
 s,@USE_DELAY_POOLS_FALSE@,$USE_DELAY_POOLS_FALSE,;t t
218
+s,@USE_ICAP_TRUE@,$USE_ICAP_TRUE,;t t
219
+s,@USE_ICAP_FALSE@,$USE_ICAP_FALSE,;t t
220
 s,@USE_SNMP_TRUE@,$USE_SNMP_TRUE,;t t
221
 s,@USE_SNMP_FALSE@,$USE_SNMP_FALSE,;t t
222
 s,@SNMPLIB@,$SNMPLIB,;t t
223
@@ -18599,6 +18728,10 @@
224
 s,@USE_KQUEUE_FALSE@,$USE_KQUEUE_FALSE,;t t
225
 s,@NEED_OWN_SNPRINTF_TRUE@,$NEED_OWN_SNPRINTF_TRUE,;t t
226
 s,@NEED_OWN_SNPRINTF_FALSE@,$NEED_OWN_SNPRINTF_FALSE,;t t
227
+s,@NEED_OWN_STRNSTR_TRUE@,$NEED_OWN_STRNSTR_TRUE,;t t
228
+s,@NEED_OWN_STRNSTR_FALSE@,$NEED_OWN_STRNSTR_FALSE,;t t
229
+s,@NEED_OWN_STRCASESTR_TRUE@,$NEED_OWN_STRCASESTR_TRUE,;t t
230
+s,@NEED_OWN_STRCASESTR_FALSE@,$NEED_OWN_STRCASESTR_FALSE,;t t
231
 s,@NEED_OWN_STRSEP_TRUE@,$NEED_OWN_STRSEP_TRUE,;t t
232
 s,@NEED_OWN_STRSEP_FALSE@,$NEED_OWN_STRSEP_FALSE,;t t
233
 s,@REGEXLIB@,$REGEXLIB,;t t
234
--- include/autoconf.h.in.orig Wed Jul 12 17:00:31 2006
235
+++ include/autoconf.h.in	Sat Aug  5 16:18:25 2006
236
@@ -454,6 +454,9 @@
237
 /* Define to 1 if you have the <stdlib.h> header file. */
238
 #undef HAVE_STDLIB_H
239
 
240
+/* Define to 1 if you have the `strcasestr' function. */
241
+#undef HAVE_STRCASESTR
242
+
243
 /* Define to 1 if you have the `strerror' function. */
244
 #undef HAVE_STRERROR
245
 
246
@@ -463,6 +466,9 @@
247
 /* Define to 1 if you have the <string.h> header file. */
248
 #undef HAVE_STRING_H
249
 
250
+/* Define to 1 if you have the `strnstr' function. */
251
+#undef HAVE_STRNSTR
252
+
253
 /* Define to 1 if you have the `strsep' function. */
254
 #undef HAVE_STRSEP
255
 
256
@@ -587,6 +593,9 @@
257
 
258
 /* Some systems support __va_copy */
259
 #undef HAVE___VA_COPY
260
+
261
+/* Content filtering via ICAP servers. */
262
+#undef HS_FEAT_ICAP
263
 
264
 /* By default (for now anyway) Squid includes options which allows the cache
265
    administrator to violate the HTTP protocol specification in terms of cache
266
--- lib/Makefile.in.orig Fri Sep 22 11:09:48 2006
267
+++ lib/Makefile.in	Sat Sep 19 20:05:28 2006
268
@@ -62,20 +62,23 @@
269
 am__libmiscutil_a_SOURCES_DIST = Array.c base64.c getfullhostname.c \
270
 	hash.c heap.c html_quote.c iso3307.c md5.c radix.c rfc1035.c \
271
 	rfc1123.c rfc1738.c rfc2617.c safe_inet_addr.c snprintf.c \
272
-	splay.c Stack.c strsep.c stub_memaccount.c util.c uudecode.c \
273
-	win32lib.c
274
+	splay.c Stack.c strnstr.c strcasestr.c strsep.c \
275
+	stub_memaccount.c util.c uudecode.c win32lib.c
276
 @NEED_OWN_MD5_TRUE@am__objects_1 = md5.$(OBJEXT)
277
 @NEED_OWN_SNPRINTF_TRUE@am__objects_2 = snprintf.$(OBJEXT)
278
-@NEED_OWN_STRSEP_TRUE@am__objects_3 = strsep.$(OBJEXT)
279
-@ENABLE_MINGW32SPECIFIC_TRUE@am__objects_4 = win32lib.$(OBJEXT)
280
+@NEED_OWN_STRNSTR_TRUE@am__objects_3 = strnstr.$(OBJEXT)
281
+@NEED_OWN_STRCASESTR_TRUE@am__objects_4 = strcasestr.$(OBJEXT)
282
+@NEED_OWN_STRSEP_TRUE@am__objects_5 = strsep.$(OBJEXT)
283
+@ENABLE_MINGW32SPECIFIC_TRUE@am__objects_6 = win32lib.$(OBJEXT)
284
 am_libmiscutil_a_OBJECTS = Array.$(OBJEXT) base64.$(OBJEXT) \
285
 	getfullhostname.$(OBJEXT) hash.$(OBJEXT) heap.$(OBJEXT) \
286
 	html_quote.$(OBJEXT) iso3307.$(OBJEXT) $(am__objects_1) \
287
 	radix.$(OBJEXT) rfc1035.$(OBJEXT) rfc1123.$(OBJEXT) \
288
 	rfc1738.$(OBJEXT) rfc2617.$(OBJEXT) safe_inet_addr.$(OBJEXT) \
289
 	$(am__objects_2) splay.$(OBJEXT) Stack.$(OBJEXT) \
290
-	$(am__objects_3) stub_memaccount.$(OBJEXT) util.$(OBJEXT) \
291
-	uudecode.$(OBJEXT) $(am__objects_4)
292
+	$(am__objects_3) $(am__objects_4) $(am__objects_5) \
293
+	stub_memaccount.$(OBJEXT) util.$(OBJEXT) uudecode.$(OBJEXT) \
294
+	$(am__objects_6)
295
 libmiscutil_a_OBJECTS = $(am_libmiscutil_a_OBJECTS)
296
 libntlmauth_a_AR = $(AR) $(ARFLAGS)
297
 libntlmauth_a_DEPENDENCIES = @LIBOBJS@
298
@@ -190,6 +193,10 @@
299
 NEED_OWN_MD5_TRUE = @NEED_OWN_MD5_TRUE@
300
 NEED_OWN_SNPRINTF_FALSE = @NEED_OWN_SNPRINTF_FALSE@
301
 NEED_OWN_SNPRINTF_TRUE = @NEED_OWN_SNPRINTF_TRUE@
302
+NEED_OWN_STRCASESTR_FALSE = @NEED_OWN_STRCASESTR_FALSE@
303
+NEED_OWN_STRCASESTR_TRUE = @NEED_OWN_STRCASESTR_TRUE@
304
+NEED_OWN_STRNSTR_FALSE = @NEED_OWN_STRNSTR_FALSE@
305
+NEED_OWN_STRNSTR_TRUE = @NEED_OWN_STRNSTR_TRUE@
306
 NEED_OWN_STRSEP_FALSE = @NEED_OWN_STRSEP_FALSE@
307
 NEED_OWN_STRSEP_TRUE = @NEED_OWN_STRSEP_TRUE@
308
 NEGOTIATE_AUTH_HELPERS = @NEGOTIATE_AUTH_HELPERS@
309
@@ -229,6 +236,8 @@
310
 USE_DNSSERVER_TRUE = @USE_DNSSERVER_TRUE@
311
 USE_EPOLL_FALSE = @USE_EPOLL_FALSE@
312
 USE_EPOLL_TRUE = @USE_EPOLL_TRUE@
313
+USE_ICAP_FALSE = @USE_ICAP_FALSE@
314
+USE_ICAP_TRUE = @USE_ICAP_TRUE@
315
 USE_KQUEUE_FALSE = @USE_KQUEUE_FALSE@
316
 USE_KQUEUE_TRUE = @USE_KQUEUE_TRUE@
317
 USE_POLL_FALSE = @USE_POLL_FALSE@
318
@@ -284,6 +293,10 @@
319
 target_alias = @target_alias@
320
 @NEED_OWN_SNPRINTF_FALSE@SNPRINTFSOURCE = 
321
 @NEED_OWN_SNPRINTF_TRUE@SNPRINTFSOURCE = snprintf.c
322
+@NEED_OWN_STRNSTR_FALSE@STRNSTRSOURCE = 
323
+@NEED_OWN_STRNSTR_TRUE@STRNSTRSOURCE = strnstr.c
324
+@NEED_OWN_STRCASESTR_FALSE@STRCASESTRSOURCE = 
325
+@NEED_OWN_STRCASESTR_TRUE@STRCASESTRSOURCE = strcasestr.c
326
 @NEED_OWN_STRSEP_FALSE@STRSEPSOURCE = 
327
 @NEED_OWN_STRSEP_TRUE@STRSEPSOURCE = strsep.c
328
 @NEED_OWN_MD5_FALSE@MD5SOURCE = 
329
@@ -328,6 +341,8 @@
330
 	$(SNPRINTFSOURCE) \
331
 	splay.c \
332
 	Stack.c \
333
+	$(STRNSTRSOURCE) \
334
+	$(STRCASESTRSOURCE) \
335
 	$(STRSEPSOURCE) \
336
 	stub_memaccount.c \
337
 	util.c \
338
@@ -443,6 +458,8 @@
339
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snprintf.Po@am__quote@
340
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/splay.Po@am__quote@
341
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sspwin32.Po@am__quote@
342
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strcasestr.Po@am__quote@
343
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strnstr.Po@am__quote@
344
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strsep.Po@am__quote@
345
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stub_memaccount.Po@am__quote@
346
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@
(-)files/patch-aa (-11 lines)
Lines 1-11 Link Here
1
--- include/squid_types.h.orig Mon Jul  7 00:45:26 2003
2
+++ include/squid_types.h      Mon Jul  7 00:48:39 2003
3
@@ -66,8 +66,5 @@
4
 #if HAVE_SYS_TYPES_H
5
 #include <sys/types.h>
6
 #endif
7
-#if HAVE_SYS_BITYPES_H
8
-#include <sys/bitypes.h>
9
-#endif
10
11
 #endif /* SQUID_TYPES_H */
(-)files/patch-src-cf.data.pre (-25 / +3 lines)
Lines 1-29 Link Here
1
--- src/cf.data.pre.orig	Thu Oct 12 22:48:48 2006
1
--- src/cf.data.pre.orig	Tue Apr 17 00:10:49 2007
2
+++ src/cf.data.pre	Wed Nov  8 18:56:47 2006
2
+++ src/cf.data.pre	Thu May 17 15:13:37 2007
3
@@ -1183,6 +1183,21 @@
3
@@ -3047,12 +3062,12 @@
4
 
4
 
5
 	Note that for coss, max-size must be less than COSS_MEMBUF_SZ
6
 	(hard coded at 1 MB).
7
+
8
+	Note for FreeBSD users:
9
+	COSS -- like aufs -- uses async IO so if you compiled Squid without
10
+	support for the aufs storage type, COSS will use POSIX AIO.
11
+	This means that you need to add the line
12
+
13
+	options VFS_AIO
14
+
15
+	to your kernel configuration in order to use COSS.
16
+
17
+	On FreeBSD 5 and higher you can load the aio(4) module and do not
18
+	necessarily need to recompile your kernel.
19
+
20
+	If you compiled Squid with both support for aufs and COSS, COSS
21
+	will use aufs' routines and does not need special kernel support.
22
 DOC_END
23
 
24
 NAME: logformat
25
@@ -3280,12 +3295,12 @@
26
 
27
 NAME: cache_effective_user
5
 NAME: cache_effective_user
28
 TYPE: string
6
 TYPE: string
29
-DEFAULT: nobody
7
-DEFAULT: nobody

Return to bug 113155