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