nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /* source: xio-proxy.c */
2 /* Copyright Gerhard Rieger */
3 /* Published under the GNU General Public License V.2, see file COPYING */
4  
5 /* this file contains the source for opening addresses of HTTP proxy CONNECT
6 type */
7  
8 #include "xiosysincludes.h"
9  
10 #if WITH_PROXY
11  
12 #include "xioopen.h"
13 #include "xio-socket.h"
14 #include "xio-ipapp.h"
15 #include "xio-ascii.h" /* for base64 encoding of authentication */
16  
17 #include "xio-proxy.h"
18  
19  
20 #define PROXYPORT "8080"
21  
22 static int xioopen_proxy_connect2(int argc, const char *argv[], struct opt *opts,
23 int xioflags, xiofile_t *xxfd,
24 unsigned groups, int dummy1, int dummy2,
25 int dummy3);
26 static int xioopen_proxy_connect3(int argc, const char *argv[], struct opt *opts,
27 int xioflags, xiofile_t *xxfd,
28 unsigned groups, int dummy1, int dummy2,
29 int dummy3);
30  
31 const struct optdesc opt_proxyport = { "proxyport", NULL, OPT_PROXYPORT, GROUP_HTTP, PH_LATE, TYPE_STRING, OFUNC_SPEC };
32 const struct optdesc opt_ignorecr = { "ignorecr", NULL, OPT_IGNORECR, GROUP_HTTP, PH_LATE, TYPE_BOOL, OFUNC_SPEC };
33 const struct optdesc opt_proxy_resolve = { "proxy-resolve", "resolve", OPT_PROXY_RESOLVE, GROUP_HTTP, PH_LATE, TYPE_BOOL, OFUNC_SPEC };
34 const struct optdesc opt_proxy_authorization = { "proxy-authorization", "proxyauth", OPT_PROXY_AUTHORIZATION, GROUP_HTTP, PH_LATE, TYPE_STRING, OFUNC_SPEC };
35  
36 static const struct xioaddr_inter_desc xioaddr_proxy_connect2 = { XIOADDR_INTER, "proxy", 2, XIOBIT_ALL, GROUP_HTTP|GROUP_CHILD|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_proxy_connect2, 0, 0, 0, XIOBIT_RDWR HELP(":<host>:<port>") };
37  
38 static const struct xioaddr_endpoint_desc xioaddr_proxy_connect3 = { XIOADDR_ENDPOINT, "proxy", 3, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_HTTP|GROUP_CHILD|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_proxy_connect3, 0, 0, 0 HELP(":<proxy-server>:<host>:<port>") };
39  
40 const union xioaddr_desc *xioaddrs_proxy_connect[] = {
41 (union xioaddr_desc *)&xioaddr_proxy_connect2,
42 (union xioaddr_desc *)&xioaddr_proxy_connect3,
43 NULL
44 };
45  
46 /*0#define CONNLEN 40*/ /* "CONNECT 123.156.189.123:65432 HTTP/1.0\r\n\0" */
47 #define CONNLEN 281 /* "CONNECT <255bytes>:65432 HTTP/1.0\r\n\0" */
48  
49 /* states during receiving answer */
50 enum {
51 XIOSTATE_HTTP1, /* 0 or more bytes of first line received, no \r */
52 XIOSTATE_HTTP2, /* first line received including \r */
53 XIOSTATE_HTTP3, /* received status and \r\n */
54 XIOSTATE_HTTP4, /* within header */
55 XIOSTATE_HTTP5, /* within header, \r */
56 XIOSTATE_HTTP6, /* received status and 1 or more headers, \r\n */
57 XIOSTATE_HTTP7, /* received status line, ev. headers, \r\n\r */
58 XIOSTATE_HTTP8, /* complete answer received */
59 XIOSTATE_ERROR /* error during HTTP headers */
60 } ;
61  
62  
63 /* get buflen bytes from proxy server;
64 handles EINTR;
65 returns <0 when error occurs
66 */
67 static ssize_t
68 xioproxy_recvbytes(struct single *xfd, char *buff, size_t buflen, int level) {
69 ssize_t result;
70 do {
71 /* we need at least 16 bytes... */
72 result = Read(xfd->rfd, buff, buflen);
73 } while (result < 0 && errno == EINTR); /*! EAGAIN? */
74 if (result < 0) {
75 Msg4(level, "read(%d, %p, "F_Zu"): %s",
76 xfd->rfd, buff, buflen, strerror(errno));
77 return result;
78 }
79 if (result == 0) {
80 Msg(level, "proxy_connect: connection closed by proxy");
81 }
82 return result;
83 }
84  
85  
86 #define BUFLEN 2048
87  
88  
89 static int xioopen_proxy_connect2(int argc, const char *argv[], struct opt *opts,
90 int xioflags, xiofile_t *xxfd,
91 unsigned groups, int dummy1, int dummy2,
92 int dummy3) {
93 struct single *xfd = &xxfd->stream;
94 struct proxyvars struct_proxyvars = { 0 }, *proxyvars = &struct_proxyvars;
95 const char *targetname, *targetport;
96 /* variables to be filled with address option values */
97 bool dofork = false;
98 int result;
99  
100 if (xfd->rfd < 0) {
101 Error("xioopen_proxy_connect(): proxyname missing");
102 return STAT_NORETRY;
103 }
104 targetname = argv[1];
105 targetport = argv[2];
106  
107 if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
108 applyopts(-1, opts, PH_INIT);
109  
110 retropt_bool(opts, OPT_FORK, &dofork);
111 if (dofork && !(xioflags & XIO_MAYFORK)) {
112 Error("fork option not allowed by application");
113 }
114  
115 result = _xioopen_proxy_prepare(proxyvars, opts, targetname, targetport);
116 if (result != STAT_OK) return result;
117  
118 Notice2("opening connection to %s:%u using proxy CONNECT",
119 proxyvars->targetaddr, proxyvars->targetport);
120  
121 xfd->dtype = XIODATA_STREAM;
122  
123 applyopts(xfd->rfd, opts, PH_ALL);
124 /*!*/
125  
126 if ((result = _xio_openlate(xfd, opts)) < 0)
127 return result;
128  
129 result = _xioopen_proxy_connect(xfd, proxyvars, E_ERROR);
130 switch (result) {
131 case STAT_OK: break;
132 default:
133 return result;
134 }
135  
136 Notice2("successfully connected to %s:%u via proxy",
137 proxyvars->targetaddr, proxyvars->targetport);
138 return STAT_OK;
139 }
140  
141 static int xioopen_proxy_connect3(int argc, const char *argv[], struct opt *opts,
142 int xioflags, xiofile_t *xxfd,
143 unsigned groups, int dummy1, int dummy2,
144 int dummy3) {
145 /* we expect the form: host:host:port */
146 struct single *xfd = &xxfd->stream;
147 int rw = (xioflags & XIO_ACCMODE);
148 struct proxyvars struct_proxyvars = { 0 }, *proxyvars = &struct_proxyvars;
149 const char *proxyname;
150 char *proxyport = NULL;
151 const char *targetname, *targetport;
152 /* variables to be filled with address option values */
153 bool dofork = false;
154 int socktype = SOCK_STREAM;
155 struct opt *opts0 = NULL;
156 /* */
157 int pf = PF_UNSPEC;
158 union sockaddr_union us_sa, *us = &us_sa;
159 union sockaddr_union them_sa, *them = &them_sa;
160 socklen_t uslen = sizeof(us_sa);
161 socklen_t themlen = sizeof(them_sa);
162 int ipproto = IPPROTO_TCP;
163 bool needbind = false;
164 bool lowport = false;
165 int level;
166 int result;
167  
168 if (xfd->rfd >= 0) {
169 Error("xioopen_proxy_connect(): proxyname not allowed here");
170 return STAT_NORETRY;
171 }
172 proxyname = argv[1];
173 targetname = argv[2];
174 targetport = argv[3];
175  
176 xfd->howtoshut = XIOSHUT_DOWN;
177 xfd->howtoclose = XIOCLOSE_CLOSE;
178  
179 if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
180 applyopts(-1, opts, PH_INIT);
181  
182 retropt_int(opts, OPT_SO_TYPE, &socktype);
183  
184 retropt_bool(opts, OPT_FORK, &dofork);
185 if (dofork && !(xioflags & XIO_MAYFORK)) {
186 Error("fork option not allowed by application");
187 }
188  
189 if (retropt_string(opts, OPT_PROXYPORT, &proxyport) < 0) {
190 if ((proxyport = strdup(PROXYPORT)) == NULL) {
191 errno = ENOMEM; return -1;
192 }
193 }
194  
195 result = _xioopen_proxy_prepare(proxyvars, opts, targetname, targetport);
196 if (result != STAT_OK) return result;
197  
198 result =
199 _xioopen_ipapp_prepare(opts, &opts0, proxyname, proxyport,
200 &pf, ipproto,
201 xfd->para.socket.ip.res_opts[1],
202 xfd->para.socket.ip.res_opts[0],
203 them, &themlen, us, &uslen,
204 &needbind, &lowport, socktype);
205 if (result != STAT_OK) return result;
206 Notice4("opening connection to %s:%u via proxy %s:%s",
207 proxyvars->targetaddr, proxyvars->targetport, proxyname, proxyport);
208  
209 do { /* loop over failed connect and proxy connect attempts */
210  
211 #if WITH_RETRY
212 if (xfd->forever || xfd->retry) {
213 level = E_INFO;
214 } else
215 #endif /* WITH_RETRY */
216 level = E_ERROR;
217  
218 result =
219 _xioopen_connect(xfd,
220 needbind?(struct sockaddr *)us:NULL, sizeof(*us),
221 (struct sockaddr *)them, themlen,
222 opts, pf, socktype, IPPROTO_TCP, lowport, level);
223 switch (result) {
224 case STAT_OK: break;
225 #if WITH_RETRY
226 case STAT_RETRYLATER:
227 case STAT_RETRYNOW:
228 if (xfd->forever || xfd->retry--) {
229 if (result == STAT_RETRYLATER) Nanosleep(&xfd->intervall, NULL);
230 continue;
231 }
232 #endif /* WITH_RETRY */
233 default:
234 return result;
235 }
236 if (XIOWITHWR(rw)) xfd->wfd = xfd->rfd;
237 if (!XIOWITHRD(rw)) xfd->rfd = -1;
238  
239 applyopts(xfd->rfd, opts, PH_ALL);
240 /*!*/
241  
242 if ((result = _xio_openlate(xfd, opts)) < 0)
243 return result;
244  
245 result = _xioopen_proxy_connect(xfd, proxyvars, level);
246 switch (result) {
247 case STAT_OK: break;
248 #if WITH_RETRY
249 case STAT_RETRYLATER:
250 case STAT_RETRYNOW:
251 if (xfd->forever || xfd->retry--) {
252 if (result == STAT_RETRYLATER) Nanosleep(&xfd->intervall, NULL);
253 continue;
254 }
255 #endif /* WITH_RETRY */
256 default:
257 return result;
258 }
259  
260 if (dofork) {
261 xiosetchilddied(); /* set SIGCHLD handler */
262 }
263  
264 #if WITH_RETRY
265 if (dofork) {
266 pid_t pid;
267 int level = E_ERROR;
268 if (xfd->forever || xfd->retry) {
269 level = E_WARN;
270 }
271 while ((pid = xio_fork(false, level)) < 0) {
272 if (xfd->forever || --xfd->retry) {
273 Nanosleep(&xfd->intervall, NULL); continue;
274 }
275 return STAT_RETRYLATER;
276 }
277  
278 if (pid == 0) { /* child process */
279 xfd->forever = false; xfd->retry = 0;
280 break;
281 }
282  
283 /* parent process */
284 Notice1("forked off child process "F_pid, pid);
285 Close(xfd->rfd);
286 Close(xfd->wfd);
287 Nanosleep(&xfd->intervall, NULL);
288 dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
289 continue;
290 } else
291 #endif /* WITH_RETRY */
292 {
293 break;
294 }
295  
296 } while (true); /* end of complete open loop - drop out on success */
297  
298 Notice2("successfully connected to %s:%u via proxy",
299 proxyvars->targetaddr, proxyvars->targetport);
300  
301 return 0;
302 }
303  
304  
305 int _xioopen_proxy_prepare(struct proxyvars *proxyvars, struct opt *opts,
306 const char *targetname, const char *targetport) {
307 struct hostent *host;
308  
309 retropt_bool(opts, OPT_IGNORECR, &proxyvars->ignorecr);
310 retropt_bool(opts, OPT_PROXY_RESOLVE, &proxyvars->doresolve);
311 retropt_string(opts, OPT_PROXY_AUTHORIZATION, &proxyvars->authstring);
312  
313 if (proxyvars->doresolve) {
314 /* currently we only resolve to IPv4 addresses. This is in accordance to
315 RFC 2396; however once it becomes clear how IPv6 addresses should be
316 represented in CONNECT commands this code might be extended */
317 host = Gethostbyname(targetname);
318 if (host == NULL) {
319 int level = E_WARN;
320 /* note: cast is req on AIX: */
321 Msg2(level, "gethostbyname(\"%s\"): %s", targetname,
322 h_errno == NETDB_INTERNAL ? strerror(errno) :
323 (char *)hstrerror(h_errno)/*0 h_messages[h_errno-1]*/);
324  
325 proxyvars->targetaddr = strdup(targetname);
326 } else {
327 #define LEN 16 /* www.xxx.yyy.zzz\0 */
328 if ((proxyvars->targetaddr = Malloc(LEN)) == NULL) {
329 return STAT_RETRYLATER;
330 }
331 snprintf(proxyvars->targetaddr, LEN, "%u.%u.%u.%u",
332 (unsigned char)host->h_addr_list[0][0],
333 (unsigned char)host->h_addr_list[0][1],
334 (unsigned char)host->h_addr_list[0][2],
335 (unsigned char)host->h_addr_list[0][3]);
336 #undef LEN
337 }
338 } else {
339 proxyvars->targetaddr = strdup(targetname);
340 }
341  
342 proxyvars->targetport = htons(parseport(targetport, IPPROTO_TCP));
343  
344 return STAT_OK;
345 }
346  
347 int _xioopen_proxy_connect(struct single *xfd,
348 struct proxyvars *proxyvars,
349 int level) {
350 size_t offset;
351 char request[CONNLEN]; /* HTTP connection request line */
352 int rv;
353 char buff[BUFLEN+1]; /* for receiving HTTP reply headers */
354 #if CONNLEN > BUFLEN
355 #error not enough buffer space
356 #endif
357 char textbuff[2*BUFLEN+1]; /* just for sanitizing print data */
358 char *eol = buff;
359 int state;
360 ssize_t sresult;
361  
362 /* generate proxy request header - points to final target */
363 rv = snprintf(request, CONNLEN, "CONNECT %s:%u HTTP/1.0\r\n",
364 proxyvars->targetaddr, proxyvars->targetport);
365 if (rv >= CONNLEN || rv < 0) {
366 Error("_xioopen_proxy_connect(): PROXY CONNECT buffer too small");
367 return -1;
368 }
369  
370 /* send proxy CONNECT request (target addr+port) */
371 * xiosanitize(request, strlen(request), textbuff) = '\0';
372 Info1("sending \"%s\"", textbuff);
373 /* write errors are assumed to always be hard errors, no retry */
374 if (writefull(xfd->wfd, request, strlen(request)) < 0) {
375 Msg4(level, "write(%d, %p, "F_Zu"): %s",
376 xfd->wfd, request, strlen(request), strerror(errno));
377 if (Close(xfd->wfd) < 0) {
378 Info2("close(%d): %s", xfd->wfd, strerror(errno));
379 }
380 return STAT_RETRYLATER;
381 }
382  
383 if (proxyvars->authstring) {
384 /* send proxy authentication header */
385 # define XIOAUTHHEAD "Proxy-authorization: Basic "
386 # define XIOAUTHLEN 27
387 static const char *authhead = XIOAUTHHEAD;
388 # define HEADLEN 256
389 char *header, *next;
390  
391 /* ...\r\n\0 */
392 if ((header =
393 Malloc(XIOAUTHLEN+((strlen(proxyvars->authstring)+2)/3)*4+3))
394 == NULL) {
395 return -1;
396 }
397 strcpy(header, authhead);
398 next = xiob64encodeline(proxyvars->authstring,
399 strlen(proxyvars->authstring),
400 strchr(header, '\0'));
401 *next = '\0';
402 Info1("sending \"%s\\r\\n\"", header);
403 *next++ = '\r'; *next++ = '\n'; *next++ = '\0';
404 if (writefull(xfd->wfd, header, strlen(header)) < 0) {
405 Msg4(level, "write(%d, %p, "F_Zu"): %s",
406 xfd->wfd, header, strlen(header), strerror(errno));
407 if (Close(xfd->wfd/*!*/) < 0) {
408 Info2("close(%d): %s", xfd->wfd, strerror(errno));
409 }
410 return STAT_RETRYLATER;
411 }
412  
413 free(header);
414 }
415  
416 Info("sending \"\\r\\n\"");
417 if (writefull(xfd->wfd, "\r\n", 2) < 0) {
418 Msg2(level, "write(%d, \"\\r\\n\", 2): %s",
419 xfd->wfd, strerror(errno));
420 if (Close(xfd->wfd) < 0) {
421 Info2("close(%d): %s", xfd->wfd, strerror(errno));
422 }
423 return STAT_RETRYLATER;
424 }
425  
426 /* request is kept for later error messages */
427 *strstr(request, " HTTP") = '\0';
428  
429 /* receive proxy answer; looks like "HTTP/1.0 200 .*\r\nHeaders..\r\n\r\n" */
430 /* socat version 1 depends on a valid fd for data transfer; address
431 therefore cannot buffer data. So, to prevent reading beyond the end of
432 the answer headers, only single bytes are read. puh. */
433 state = XIOSTATE_HTTP1;
434 offset = 0; /* up to where the buffer is filled (relative) */
435 /*eol;*/ /* points to the first lineterm of the current line */
436 do {
437 sresult = xioproxy_recvbytes(xfd, buff+offset, 1, level);
438 if (sresult <= 0) {
439 state = XIOSTATE_ERROR;
440 break; /* leave read cycles */
441 }
442  
443 switch (state) {
444  
445 case XIOSTATE_HTTP1:
446 /* 0 or more bytes of first line received, no '\r' yet */
447 if (*(buff+offset) == '\r') {
448 eol = buff+offset;
449 state = XIOSTATE_HTTP2;
450 break;
451 }
452 if (proxyvars->ignorecr && *(buff+offset) == '\n') {
453 eol = buff+offset;
454 state = XIOSTATE_HTTP3;
455 break;
456 }
457 break;
458  
459 case XIOSTATE_HTTP2:
460 /* first line received including '\r' */
461 if (*(buff+offset) != '\n') {
462 state = XIOSTATE_HTTP1;
463 break;
464 }
465 state = XIOSTATE_HTTP3;
466 break;
467  
468 case XIOSTATE_HTTP3:
469 /* received status (first line) and "\r\n" */
470 if (*(buff+offset) == '\r') {
471 state = XIOSTATE_HTTP7;
472 break;
473 }
474 if (proxyvars->ignorecr && *(buff+offset) == '\n') {
475 state = XIOSTATE_HTTP8;
476 break;
477 }
478 state = XIOSTATE_HTTP4;
479 break;
480  
481 case XIOSTATE_HTTP4:
482 /* within header */
483 if (*(buff+offset) == '\r') {
484 eol = buff+offset;
485 state = XIOSTATE_HTTP5;
486 break;
487 }
488 if (proxyvars->ignorecr && *(buff+offset) == '\n') {
489 eol = buff+offset;
490 state = XIOSTATE_HTTP6;
491 break;
492 }
493 break;
494  
495 case XIOSTATE_HTTP5:
496 /* within header, '\r' received */
497 if (*(buff+offset) != '\n') {
498 state = XIOSTATE_HTTP4;
499 break;
500 }
501 state = XIOSTATE_HTTP6;
502 break;
503  
504 case XIOSTATE_HTTP6:
505 /* received status (first line) and 1 or more headers, "\r\n" */
506 if (*(buff+offset) == '\r') {
507 state = XIOSTATE_HTTP7;
508 break;
509 }
510 if (proxyvars->ignorecr && *(buff+offset) == '\n') {
511 state = XIOSTATE_HTTP8;
512 break;
513 }
514 state = XIOSTATE_HTTP4;
515 break;
516  
517 case XIOSTATE_HTTP7:
518 /* received status (first line), 0 or more headers, "\r\n\r" */
519 if (*(buff+offset) == '\n') {
520 state = XIOSTATE_HTTP8;
521 break;
522 }
523 if (*(buff+offset) == '\r') {
524 if (proxyvars->ignorecr) {
525 break; /* ignore it, keep waiting for '\n' */
526 } else {
527 state = XIOSTATE_HTTP5;
528 }
529 break;
530 }
531 state = XIOSTATE_HTTP4;
532 break;
533  
534 }
535 ++offset;
536  
537 /* end of status line reached */
538 if (state == XIOSTATE_HTTP3) {
539 char *ptr;
540 /* set a terminating null - on or after CRLF? */
541 *(buff+offset) = '\0';
542  
543 * xiosanitize(buff, Min(offset, (sizeof(textbuff)-1)>>1), textbuff)
544 = '\0';
545 Info1("proxy_connect: received answer \"%s\"", textbuff);
546 *eol = '\0';
547 * xiosanitize(buff, Min(strlen(buff), (sizeof(textbuff)-1)>>1),
548 textbuff) = '\0';
549 if (strncmp(buff, "HTTP/1.0 ", 9) &&
550 strncmp(buff, "HTTP/1.1 ", 9)) {
551 /* invalid answer */
552 Msg1(level, "proxy: invalid answer \"%s\"", textbuff);
553 return STAT_RETRYLATER;
554 }
555 ptr = buff+9;
556  
557 /* skip multiple spaces */
558 while (*ptr == ' ') ++ptr;
559  
560 /* HTTP answer */
561 if (strncmp(ptr, "200", 3)) {
562 /* not ok */
563 /* CERN:
564 "HTTP/1.0 200 Connection established"
565 "HTTP/1.0 400 Invalid request "CONNECT 10.244.9.3:8080 HTTP/1.0" (unknown method)"
566 "HTTP/1.0 403 Forbidden - by rule"
567 "HTTP/1.0 407 Proxy Authentication Required"
568 Proxy-Authenticate: Basic realm="Squid proxy-caching web server"
569 > 50 72 6f 78 79 2d 61 75 74 68 6f 72 69 7a 61 74 Proxy-authorizat
570 > 69 6f 6e 3a 20 42 61 73 69 63 20 61 57 4e 6f 63 ion: Basic aWNoc
571 > 32 56 73 59 6e 4e 30 4f 6e 4e 30 63 6d 56 75 5a 2VsYnN0OnN0cmVuZ
572 > 32 64 6c 61 47 56 70 62 51 3d 3d 0d 0a 2dlaGVpbQ==..
573 b64encode("username:password")
574 "HTTP/1.0 500 Can't connect to host"
575 */
576 /* Squid:
577 "HTTP/1.0 400 Bad Request"
578 "HTTP/1.0 403 Forbidden"
579 "HTTP/1.0 503 Service Unavailable"
580 interesting header: "X-Squid-Error: ERR_CONNECT_FAIL 111" */
581 /* Apache:
582 "HTTP/1.0 400 Bad Request"
583 "HTTP/1.1 405 Method Not Allowed"
584 */
585 /* WTE:
586 "HTTP/1.1 200 Connection established"
587 "HTTP/1.1 404 Host not found or not responding, errno: 79"
588 "HTTP/1.1 404 Host not found or not responding, errno: 32"
589 "HTTP/1.1 404 Host not found or not responding, errno: 13"
590 */
591 /* IIS:
592 "HTTP/1.1 404 Object Not Found"
593 */
594 ptr += 3;
595 while (*ptr == ' ') ++ptr;
596  
597 Msg2(level, "%s: %s", request, ptr);
598 return STAT_RETRYLATER;
599 }
600  
601 /* ok!! */
602 /* "HTTP/1.0 200 Connection established" */
603 /*Info1("proxy: \"%s\"", textbuff+13);*/
604 offset = 0;
605  
606 } else if (state == XIOSTATE_HTTP6) {
607 /* end of a header line reached */
608 char *endp;
609  
610 /* set a terminating null */
611 *(buff+offset) = '\0';
612  
613 endp =
614 xiosanitize(buff, Min(offset, (sizeof(textbuff)-1)>>1),
615 textbuff);
616 *endp = '\0';
617 Info1("proxy_connect: received header \"%s\"", textbuff);
618 offset = 0;
619 }
620  
621 } while (state != XIOSTATE_HTTP8 && offset < BUFLEN);
622  
623 if (state == XIOSTATE_ERROR) {
624 return STAT_RETRYLATER;
625 }
626  
627 if (offset >= BUFLEN) {
628 Msg1(level, "proxy answer exceeds %d bytes, aborting", BUFLEN);
629 return STAT_NORETRY;
630 }
631  
632 return STAT_OK;
633 }
634  
635 #endif /* WITH_PROXY */
636