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ä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ögliche Gründe: |
439 |
+<UL> |
440 |
+<LI>Nicht erreichbarer ICAP-Server |
441 |
+<LI>Ungü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 |
} |