Fix bug#739 (proxy/shutdown)
[gnupg.git] / util / http.c
1 /* http.c  -  HTTP protocol handler
2  * Copyright (C) 1999, 2001, 2002, 2003, 2004,
3  *               2005 Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
20  * USA.
21  */
22
23 #include <config.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <stdarg.h>
27 #include <string.h>
28 #include <ctype.h>
29 #include <errno.h>
30
31 #ifdef _WIN32
32 #include <windows.h>
33 #else
34 #include <unistd.h>
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <sys/time.h>
38 #include <time.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
41 #include <netdb.h>
42 #endif
43
44 #include "util.h"
45 #include "iobuf.h"
46 #include "i18n.h"
47 #include "http.h"
48 #include "srv.h"
49
50 #ifdef _WIN32
51 #define sock_close(a)  closesocket(a)
52 #else
53 #define sock_close(a)  close(a)
54 #endif
55
56 #define MAX_LINELEN 20000  /* max. length of a HTTP line */
57 #define VALID_URI_CHARS "abcdefghijklmnopqrstuvwxyz"   \
58                         "ABCDEFGHIJKLMNOPQRSTUVWXYZ"   \
59                         "01234567890@"                 \
60                         "!\"#$%&'()*+,-./:;<=>?[\\]^_{|}~"
61
62 #ifndef EAGAIN
63 #define EAGAIN  EWOULDBLOCK
64 #endif
65
66 static int parse_uri( PARSED_URI *ret_uri, const char *uri );
67 static void release_parsed_uri( PARSED_URI uri );
68 static int do_parse_uri( PARSED_URI uri, int only_local_part );
69 static int remove_escapes( byte *string );
70 static int insert_escapes( byte *buffer, const byte *string,
71                                          const byte *special );
72 static URI_TUPLE parse_tuple( byte *string );
73 static int send_request( HTTP_HD hd, const char *auth, const char *proxy );
74 static byte *build_rel_path( PARSED_URI uri );
75 static int parse_response( HTTP_HD hd );
76
77 static int connect_server( const char *server, ushort port, unsigned int flags,
78                            const char *srvtag );
79 static int write_server( int sock, const char *data, size_t length );
80
81 #ifdef _WIN32
82 static void
83 deinit_sockets (void)
84 {
85     WSACleanup();
86 }
87
88 static void
89 init_sockets (void)
90 {
91     static int initialized;
92     static WSADATA wsdata;
93
94     if (initialized)
95         return;
96
97     if( WSAStartup( 0x0101, &wsdata ) ) {
98         log_error ("error initializing socket library: ec=%d\n", 
99                     (int)WSAGetLastError () );
100         return;
101     }
102     if( wsdata.wVersion < 0x0001 ) {
103         log_error ("socket library version is %x.%x - but 1.1 needed\n",
104                    LOBYTE(wsdata.wVersion), HIBYTE(wsdata.wVersion));
105         WSACleanup();
106         return;
107     }
108     atexit ( deinit_sockets );
109     initialized = 1;
110 }
111 #endif /*_WIN32*/
112
113 static byte bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
114                          "abcdefghijklmnopqrstuvwxyz"
115                          "0123456789+/";
116
117 /****************
118  * create a radix64 encoded string.
119  */
120
121 /* TODO: This is a duplicate of code in g10/armor.c modified to do the
122    "=" padding.  Better to use a single copy in strgutil.c ? */
123 static char *
124 make_radix64_string( const byte *data, size_t len )
125 {
126     char *buffer, *p;
127
128     buffer = p = xmalloc( (len+2)/3*4 + 1 );
129     for( ; len >= 3 ; len -= 3, data += 3 ) {
130         *p++ = bintoasc[(data[0] >> 2) & 077];
131         *p++ = bintoasc[(((data[0] <<4)&060)|((data[1] >> 4)&017))&077];
132         *p++ = bintoasc[(((data[1]<<2)&074)|((data[2]>>6)&03))&077];
133         *p++ = bintoasc[data[2]&077];
134     }
135     if( len == 2 ) {
136         *p++ = bintoasc[(data[0] >> 2) & 077];
137         *p++ = bintoasc[(((data[0] <<4)&060)|((data[1] >> 4)&017))&077];
138         *p++ = bintoasc[((data[1]<<2)&074)];
139         *p++ = '=';
140     }
141     else if( len == 1 ) {
142         *p++ = bintoasc[(data[0] >> 2) & 077];
143         *p++ = bintoasc[(data[0] <<4)&060];
144         *p++ = '=';
145         *p++ = '=';
146     }
147     *p = 0;
148     return buffer;
149 }
150
151 int
152 http_open( HTTP_HD hd, HTTP_REQ_TYPE reqtype, const char *url,
153            char *auth, unsigned int flags, const char *proxy )
154 {
155     int rc;
156
157     if( !(reqtype == HTTP_REQ_GET || reqtype == HTTP_REQ_POST) )
158         return G10ERR_INV_ARG;
159
160     /* initialize the handle */
161     memset( hd, 0, sizeof *hd );
162     hd->sock = -1;
163     hd->initialized = 1;
164     hd->req_type = reqtype;
165     hd->flags = flags;
166
167     rc = parse_uri( &hd->uri, url );
168     if( !rc ) {
169         rc = send_request( hd, auth, proxy );
170         if( !rc ) {
171             hd->fp_write = iobuf_sockopen( hd->sock , "w" );
172             if( hd->fp_write )
173                 return 0;
174             rc = G10ERR_GENERAL;
175         }
176     }
177
178     if( !hd->fp_read && !hd->fp_write && hd->sock != -1 )
179         sock_close( hd->sock );
180     iobuf_close( hd->fp_read );
181     iobuf_close( hd->fp_write);
182     release_parsed_uri( hd->uri );
183     hd->initialized = 0;
184
185     return rc;
186 }
187
188
189 void
190 http_start_data( HTTP_HD hd )
191 {
192     iobuf_flush ( hd->fp_write );
193     if( !hd->in_data ) {
194         write_server (hd->sock, "\r\n", 2);
195         hd->in_data = 1;
196     }
197 }
198
199
200 int
201 http_wait_response( HTTP_HD hd, unsigned int *ret_status )
202 {
203     int rc;
204
205     http_start_data( hd ); /* make sure that we are in the data */
206
207 #if 0
208     hd->sock = dup( hd->sock ); 
209     if( hd->sock == -1 )
210         return G10ERR_GENERAL;
211 #endif
212     iobuf_ioctl (hd->fp_write, 1, 1, NULL); /* keep the socket open */
213     iobuf_close (hd->fp_write);
214     hd->fp_write = NULL;
215     /* We do not want the shutdown code anymore.  It used to be there
216        to support old versions of pksd.  These versions are anyway
217        unusable and the latest releases haven been fixed to properly
218        handle HTTP 1.0. */
219     /* if ( !(hd->flags & HTTP_FLAG_NO_SHUTDOWN) ) */
220     /*     shutdown( hd->sock, 1 ); */
221     hd->in_data = 0;
222
223     hd->fp_read = iobuf_sockopen( hd->sock , "r" );
224     if( !hd->fp_read )
225         return G10ERR_GENERAL;
226
227     rc = parse_response( hd );
228     if( !rc && ret_status )
229         *ret_status = hd->status_code;
230
231     return rc;
232 }
233
234
235 int
236 http_open_document( HTTP_HD hd, const char *document, char *auth,
237                     unsigned int flags, const char *proxy )
238 {
239     int rc;
240
241     rc = http_open(hd, HTTP_REQ_GET, document, auth, flags, proxy );
242     if( rc )
243         return rc;
244
245     rc = http_wait_response( hd, NULL );
246     if( rc )
247         http_close( hd );
248
249     return rc;
250 }
251
252
253 void
254 http_close( HTTP_HD hd )
255 {
256     if( !hd || !hd->initialized )
257         return;
258     if( !hd->fp_read && !hd->fp_write && hd->sock != -1 )
259         sock_close( hd->sock );
260     iobuf_close( hd->fp_read );
261     iobuf_close( hd->fp_write );
262     release_parsed_uri( hd->uri );
263     xfree( hd->buffer );
264     hd->initialized = 0;
265 }
266
267
268
269 /****************
270  * Parse an URI and put the result into the newly allocated ret_uri.
271  * The caller must always use release_parsed_uri to releases the
272  * resources (even on an error).
273  */
274 static int
275 parse_uri( PARSED_URI *ret_uri, const char *uri )
276 {
277    *ret_uri = xmalloc_clear( sizeof(**ret_uri) + strlen(uri) );
278    strcpy( (*ret_uri)->buffer, uri );
279    return do_parse_uri( *ret_uri, 0 );
280 }
281
282 static void
283 release_parsed_uri( PARSED_URI uri )
284 {
285     if( uri )
286     {
287         URI_TUPLE r, r2;
288
289         for( r = uri->query; r; r = r2 ) {
290             r2 = r->next;
291             xfree( r );
292         }
293         xfree( uri );
294     }
295 }
296
297 static int
298 do_parse_uri( PARSED_URI uri, int only_local_part )
299 {
300     URI_TUPLE *tail;
301     char *p, *p2, *p3;
302     int n;
303
304     p = uri->buffer;
305     n = strlen( uri->buffer );
306     /* initialize all fields to an empty string or an empty list */
307     uri->scheme = uri->host = uri->path = p + n;
308     uri->port = 0;
309     uri->params = uri->query = NULL;
310
311     /* a quick validity check */
312     if( strspn( p, VALID_URI_CHARS) != n )
313         return G10ERR_BAD_URI; /* invalid characters found */
314
315     if( !only_local_part ) {
316         /* find the scheme */
317         if( !(p2 = strchr( p, ':' ) ) || p2 == p )
318            return G10ERR_BAD_URI; /* No scheme */
319         *p2++ = 0;
320         strlwr( p );
321         uri->scheme = p;
322         if(strcmp(uri->scheme,"http")==0)
323           uri->port = 80;
324         else if(strcmp(uri->scheme,"hkp")==0)
325           uri->port = 11371;
326         else
327           return G10ERR_INVALID_URI; /* Unsupported scheme */
328
329         p = p2;
330
331         /* find the hostname */
332         if( *p != '/' )
333             return G10ERR_INVALID_URI; /* does not start with a slash */
334
335         p++;
336         if( *p == '/' ) {  /* there seems to be a hostname */
337             p++;
338             if( (p2 = strchr(p, '/')) )
339                 *p2++ = 0;
340
341             /* Check for username/password encoding */
342             if((p3=strchr(p,'@')))
343               {
344                 uri->auth=p;
345                 *p3++='\0';
346                 p=p3;
347               }
348
349             strlwr( p );
350             uri->host = p;
351             if( (p3=strchr( p, ':' )) ) {
352                 *p3++ = 0;
353                 uri->port = atoi( p3 );
354             }
355
356             uri->host = p;
357             if( (n = remove_escapes( uri->host )) < 0 )
358                 return G10ERR_BAD_URI;
359             if( n != strlen( p ) )
360                 return G10ERR_BAD_URI; /* hostname with a Nul in it */
361             p = p2 ? p2 : NULL;
362         }
363     } /* end global URI part */
364
365     /* parse the pathname part */
366     if( !p || !*p ) /* we don't have a path */
367         return 0; /* and this is okay */
368
369     /* todo: here we have to check params */
370
371     /* do we have a query part */
372     if( (p2 = strchr( p, '?' )) )
373         *p2++ = 0;
374
375     uri->path = p;
376     if( (n = remove_escapes( p )) < 0 )
377         return G10ERR_BAD_URI;
378     if( n != strlen( p ) )
379         return G10ERR_BAD_URI; /* path with a Nul in it */
380     p = p2 ? p2 : NULL;
381
382     if( !p || !*p ) /* we don't have a query string */
383         return 0;   /* okay */
384
385     /* now parse the query string */
386     tail = &uri->query;
387     for(;;) {
388         URI_TUPLE elem;
389
390         if( (p2 = strchr( p, '&' )) )
391             *p2++ = 0;
392         if( !(elem = parse_tuple( p )) )
393             return G10ERR_BAD_URI;
394         *tail = elem;
395         tail = &elem->next;
396
397         if( !p2 )
398            break; /* ready */
399         p = p2;
400     }
401
402     return 0;
403 }
404
405
406
407 /****************
408  * Remove all %xx escapes; this is done inplace.
409  * Returns: new length of the string.
410  */
411 static int
412 remove_escapes( byte *string )
413 {
414     int n = 0;
415     byte *p, *s;
416
417     for(p=s=string; *s ; s++ ) {
418         if( *s == '%' ) {
419             if( s[1] && s[2] && isxdigit(s[1]) && isxdigit(s[2]) ) {
420                 s++;
421                 *p  = *s >= '0' && *s <= '9' ? *s - '0' :
422                       *s >= 'A' && *s <= 'F' ? *s - 'A' + 10 : *s - 'a' + 10 ;
423                 *p <<= 4;
424                 s++;
425                 *p |= *s >= '0' && *s <= '9' ? *s - '0' :
426                       *s >= 'A' && *s <= 'F' ? *s - 'A' + 10 : *s - 'a' + 10 ;
427                 p++;
428                 n++;
429             }
430             else {
431                 *p++ = *s++;
432                 if( *s )
433                    *p++ = *s++;
434                 if( *s )
435                    *p++ = *s++;
436                 if( *s )
437                    *p = 0;
438                 return -1; /* bad URI */
439             }
440         }
441         else
442         {
443             *p++ = *s;
444             n++;
445         }
446     }
447     *p = 0; /* always keep a string terminator */
448     return n;
449 }
450
451
452 static int
453 insert_escapes( byte *buffer, const byte *string, const byte *special )
454 {
455     int n = 0;
456
457     for( ; *string; string++ ) {
458         if( strchr( VALID_URI_CHARS, *string )
459             && !strchr( special, *string ) )  {
460             if( buffer )
461                 *buffer++ = *string;
462             n++;
463         }
464         else {
465             if( buffer ) {
466                 sprintf( buffer, "%%%02X", *string );
467                 buffer += 3;
468             }
469             n += 3;
470         }
471     }
472     return n;
473 }
474
475
476 static URI_TUPLE
477 parse_tuple( byte *string )
478 {
479     byte *p = string;
480     byte *p2;
481     int n;
482     URI_TUPLE tuple;
483
484     if( (p2 = strchr( p, '=' )) )
485         *p2++ = 0;
486     if( (n = remove_escapes( p )) < 0 )
487         return NULL; /* bad URI */
488     if( n != strlen( p ) )
489        return NULL; /* name with a Nul in it */
490     tuple = xmalloc_clear( sizeof *tuple );
491     tuple->name = p;
492     if( !p2 )  {
493         /* we have only the name, so we assume an empty value string */
494         tuple->value = p + strlen(p);
495         tuple->valuelen = 0;
496     }
497     else { /* name and value */
498         if( (n = remove_escapes( p2 )) < 0 ) {
499             xfree( tuple );
500             return NULL; /* bad URI */
501         }
502         tuple->value = p2;
503         tuple->valuelen = n;
504     }
505     return tuple;
506 }
507
508
509 /****************
510  * Send a HTTP request to the server
511  * Returns 0 if the request was successful
512  */
513 static int
514 send_request( HTTP_HD hd, const char *auth, const char *proxy )
515 {
516     const byte *server;
517     byte *request, *p;
518     ushort port;
519     int rc;
520     char *proxy_authstr=NULL,*authstr=NULL;
521
522     server = *hd->uri->host? hd->uri->host : "localhost";
523     port   = hd->uri->port?  hd->uri->port : 80;
524
525     if(proxy && *proxy)
526       {
527         PARSED_URI uri;
528
529         rc = parse_uri( &uri, proxy );
530         if (rc)
531           {
532             log_error("invalid HTTP proxy (%s): %s\n",proxy,g10_errstr(rc));
533             release_parsed_uri( uri );
534             return G10ERR_NETWORK;
535           }
536         hd->sock = connect_server( *uri->host? uri->host : "localhost",
537                                    uri->port? uri->port : 80, 0, NULL );
538         if(uri->auth)
539           {
540             char *x;
541             remove_escapes(uri->auth);
542             x=make_radix64_string(uri->auth,strlen(uri->auth));
543             proxy_authstr=xmalloc(52+strlen(x));
544             sprintf(proxy_authstr,"Proxy-Authorization: Basic %s\r\n",x);
545             xfree(x);
546           }
547
548         release_parsed_uri( uri );
549       }
550     else
551       hd->sock = connect_server( server, port, hd->flags, hd->uri->scheme );
552
553     if(auth || hd->uri->auth)
554       {
555         char *x,*tempauth=NULL;
556
557         if(auth)
558           {
559             tempauth=xstrdup(auth);
560             remove_escapes(tempauth);
561           }
562         else if(hd->uri->auth)
563           remove_escapes(hd->uri->auth);
564
565         x=make_radix64_string(tempauth?tempauth:hd->uri->auth,
566                               strlen(tempauth?tempauth:hd->uri->auth));
567         authstr=xmalloc(52+strlen(x));
568         sprintf(authstr,"Authorization: Basic %s\r\n",x);
569         xfree(x);
570         xfree(tempauth);
571       }
572
573     if( hd->sock == -1 )
574         return G10ERR_NETWORK;
575
576     p = build_rel_path( hd->uri );
577
578     request=xmalloc(strlen(server)*2 + strlen(p)
579                     + (authstr?strlen(authstr):0)
580                     + (proxy_authstr?strlen(proxy_authstr):0) + 65);
581     if( proxy && *proxy )
582       sprintf( request, "%s http://%s:%hu%s%s HTTP/1.0\r\n%s%s",
583                hd->req_type == HTTP_REQ_GET ? "GET" :
584                hd->req_type == HTTP_REQ_HEAD? "HEAD":
585                hd->req_type == HTTP_REQ_POST? "POST": "OOPS",
586                server, port,  *p == '/'? "":"/", p,
587                authstr?authstr:"",proxy_authstr?proxy_authstr:"" );
588     else
589       {
590         char portstr[15];
591
592         if(port!=80)
593           sprintf(portstr,":%u",port);
594
595         sprintf( request, "%s %s%s HTTP/1.0\r\nHost: %s%s\r\n%s",
596                  hd->req_type == HTTP_REQ_GET ? "GET" :
597                  hd->req_type == HTTP_REQ_HEAD? "HEAD":
598                  hd->req_type == HTTP_REQ_POST? "POST": "OOPS",
599                  *p == '/'? "":"/", p, server, (port!=80)?portstr:"",
600                  authstr?authstr:"");
601       }
602
603     xfree(p);
604
605     rc = write_server( hd->sock, request, strlen(request) );
606     xfree( request );
607     xfree(proxy_authstr);
608     xfree(authstr);
609
610     return rc;
611 }
612
613
614 /****************
615  * Build the relative path from the parsed URI.
616  * Minimal implementation.
617  */
618 static byte*
619 build_rel_path( PARSED_URI uri )
620 {
621     URI_TUPLE r;
622     byte *rel_path, *p;
623     int n;
624
625     /* count the needed space */
626     n = insert_escapes( NULL, uri->path, "%;?&" );
627     /* todo: build params */
628     for( r=uri->query; r; r = r->next ) {
629         n++; /* '?'/'&' */
630         n += insert_escapes( NULL, r->name, "%;?&=" );
631         n++; /* '='*/
632         n += insert_escapes( NULL, r->value, "%;?&=" );
633     }
634     n++;
635
636     /* now  allocate and copy */
637     p = rel_path = xmalloc( n );
638     n = insert_escapes( p, uri->path, "%;?&" );
639     p += n;
640     /* todo: add params */
641     for( r=uri->query; r; r = r->next ) {
642         *p++ = r == uri->query? '?':'&';
643         n = insert_escapes( p, r->name, "%;?&=" );
644         p += n;
645         *p++ = '=';
646         /* todo: use valuelen */
647         n = insert_escapes( p, r->value, "%;?&=" );
648         p += n;
649     }
650     *p = 0;
651     return rel_path;
652 }
653
654
655
656 /***********************
657  * Parse the response from a server.
658  * Returns: errorcode and sets some fileds in the handle
659  */
660 static int
661 parse_response( HTTP_HD hd )
662 {
663     byte *line, *p, *p2;
664     unsigned maxlen, len;
665
666     /* Wait for the status line */
667     do {
668         maxlen = MAX_LINELEN;
669         len = iobuf_read_line( hd->fp_read, &hd->buffer,
670                                             &hd->buffer_size, &maxlen );
671         line = hd->buffer;
672         if( !maxlen )
673             return -1; /* line has been truncated */
674         if( !len )
675             return -1; /* eof */
676     } while( !*line  );
677
678     if( (p = strchr( line, '/')) )
679         *p++ = 0;
680     if( !p || strcmp( line, "HTTP" ) )
681         return 0; /* assume http 0.9 */
682
683     if( (p2 = strpbrk( p, " \t" ) ) ) {
684         *p2++ = 0;
685         p2 += strspn( p2, " \t" );
686     }
687     if( !p2 )
688         return 0; /* assume http 0.9 */
689     p = p2;
690     /* todo: add HTTP version number check here */
691     if( (p2 = strpbrk( p, " \t" ) ) )
692         *p2++ = 0;
693     if( !isdigit(p[0]) || !isdigit(p[1]) || !isdigit(p[2]) || p[3] ) {
694          /* malformed HTTP statuscode - assume HTTP 0.9 */
695         hd->is_http_0_9 = 1;
696         hd->status_code = 200;
697         return 0;
698     }
699     hd->status_code = atoi( p );
700
701     /* skip all the header lines and wait for the empty line */
702     do {
703         maxlen = MAX_LINELEN;
704         len = iobuf_read_line( hd->fp_read, &hd->buffer,
705                                &hd->buffer_size, &maxlen );
706         line = hd->buffer;
707         /* we ignore truncated lines */
708         if( !len )
709             return -1; /* eof */
710         /* time lineendings */
711         if( (*line == '\r' && line[1] == '\n') || *line == '\n' )
712             *line = 0;
713     } while( len && *line  );
714
715     return 0;
716 }
717
718 #ifdef TEST
719 static int
720 start_server()
721 {
722     struct sockaddr_in mya;
723     struct sockaddr_in peer;
724     int fd, client;
725     fd_set rfds;
726     int addrlen;
727     int i;
728
729     if( (fd=socket(AF_INET,SOCK_STREAM, 0)) == -1 ) {
730         log_error("socket() failed: %s\n", strerror(errno));
731         return -1;
732     }
733     i = 1;
734     if( setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (byte*)&i, sizeof(i) ) )
735         log_info("setsockopt(SO_REUSEADDR) failed: %s\n", strerror(errno) );
736
737     mya.sin_family=AF_INET;
738     memset(&mya.sin_addr, 0, sizeof(mya.sin_addr));
739     mya.sin_port=htons(11371);
740
741     if( bind( fd, (struct sockaddr *)&mya, sizeof(mya)) ) {
742         log_error("bind to port 11371 failed: %s\n", strerror(errno) );
743         sock_close( fd );
744         return -1;
745     }
746
747     if( listen( fd, 5 ) ) {
748         log_error("listen failed: %s\n", strerror(errno) );
749         sock_close( fd );
750         return -1;
751     }
752
753     for(;;) {
754         FD_ZERO(&rfds);
755         FD_SET( fd, &rfds );
756
757         if( select( fd+1, &rfds, NULL, NULL, NULL) <= 0 )
758             continue; /* ignore any errors */
759
760         if( !FD_ISSET( fd, &rfds ) )
761             continue;
762
763         addrlen = sizeof peer;
764         client = accept( fd, (struct sockaddr *)&peer, &addrlen);
765         if( client == -1 )
766             continue; /* oops */
767
768         log_info("connect from %s\n", inet_ntoa( peer.sin_addr ) );
769
770         fflush(stdout);
771         fflush(stderr);
772         if( !fork() ) {
773             int c;
774             FILE *fp;
775
776             fp = fdopen( client , "r" );
777             while( (c=getc(fp)) != EOF )
778                 putchar(c);
779             fclose(fp);
780             exit(0);
781         }
782         sock_close( client );
783     }
784
785
786     return 0;
787 }
788 #endif
789
790
791 static int
792 connect_server( const char *server, ushort port, unsigned int flags,
793                 const char *srvtag )
794 {
795   int sock=-1,srv,srvcount=0,connected=0,hostfound=0;
796   struct srventry *srvlist=NULL;
797
798 #ifdef _WIN32
799   unsigned long inaddr;
800
801   init_sockets();
802   /* Win32 gethostbyname doesn't handle IP addresses internally, so we
803      try inet_addr first on that platform only. */
804   if((inaddr=inet_addr(server))!=INADDR_NONE)
805     {
806       struct sockaddr_in addr;
807
808       memset(&addr,0,sizeof(addr));
809
810       if((sock=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET)
811         {
812           log_error("error creating socket: ec=%d\n",(int)WSAGetLastError());
813           return -1;
814         }
815
816       addr.sin_family=AF_INET; 
817       addr.sin_port=htons(port);
818       memcpy(&addr.sin_addr,&inaddr,sizeof(inaddr));      
819
820       if(connect(sock,(struct sockaddr *)&addr,sizeof(addr))==0)
821         return sock;
822       else
823         {
824           sock_close(sock);
825           return -1;
826         }
827     }
828 #endif
829
830 #ifdef USE_DNS_SRV
831   /* Do the SRV thing */
832   if(flags&HTTP_FLAG_TRY_SRV && srvtag)
833     {
834       /* We're using SRV, so append the tags */
835       if(1+strlen(srvtag)+6+strlen(server)+1<=MAXDNAME)
836         {
837           char srvname[MAXDNAME];
838
839           strcpy(srvname,"_");
840           strcat(srvname,srvtag);
841           strcat(srvname,"._tcp.");
842           strcat(srvname,server);
843           srvcount=getsrv(srvname,&srvlist);
844         }
845     }
846 #endif
847
848   if(srvlist==NULL)
849     {
850       /* Either we're not using SRV, or the SRV lookup failed.  Make
851          up a fake SRV record. */
852       srvlist=xmalloc_clear(sizeof(struct srventry));
853       srvlist->port=port;
854       strncpy(srvlist->target,server,MAXDNAME);
855       srvlist->target[MAXDNAME-1]='\0';
856       srvcount=1;
857     }
858
859 #ifdef HAVE_GETADDRINFO
860
861   for(srv=0;srv<srvcount;srv++)
862     {
863       struct addrinfo hints,*res,*ai;
864       char portstr[6];
865
866       sprintf(portstr,"%u",srvlist[srv].port);
867       memset(&hints,0,sizeof(hints));
868       hints.ai_socktype=SOCK_STREAM;
869       if(getaddrinfo(srvlist[srv].target,portstr,&hints,&res)==0)
870         hostfound=1;
871       else
872         continue;
873
874       for(ai=res;ai;ai=ai->ai_next)
875         {
876           if((sock=socket(ai->ai_family,ai->ai_socktype,ai->ai_protocol))==-1)
877             {
878               log_error("error creating socket: %s\n",strerror(errno));
879               freeaddrinfo(res);
880               return -1;
881             }
882
883           if(connect(sock,ai->ai_addr,ai->ai_addrlen)==0)
884             {
885               connected=1;
886               break;
887             }
888
889           sock_close(sock);
890         }
891
892       freeaddrinfo(res);
893
894       if(ai)
895         break;
896     }
897
898 #else /* !HAVE_GETADDRINFO */
899
900   for(srv=0;srv<srvcount;srv++)
901     {
902       int i=0;
903       struct hostent *host=NULL;
904       struct sockaddr_in addr;
905
906       memset(&addr,0,sizeof(addr));
907
908       if((host=gethostbyname(srvlist[srv].target))==NULL)
909         continue;
910
911       hostfound=1;
912
913       if((sock=socket(host->h_addrtype,SOCK_STREAM,0))==-1)
914         {
915           log_error("error creating socket: %s\n",strerror(errno));
916           return -1;
917         }
918
919       addr.sin_family=host->h_addrtype;
920       if(addr.sin_family!=AF_INET)
921         {
922           log_error("%s: unknown address family\n",srvlist[srv].target);
923           return -1;
924         }
925
926       addr.sin_port=htons(srvlist[srv].port);
927
928       /* Try all A records until one responds. */
929       while(host->h_addr_list[i])
930         {
931           if(host->h_length!=4)
932             {
933               log_error("%s: illegal address length\n",srvlist[srv].target);
934               return -1;
935             }
936
937           memcpy(&addr.sin_addr,host->h_addr_list[i],host->h_length);
938
939           if(connect(sock,(struct sockaddr *)&addr,sizeof(addr))==0)
940             {
941               connected=1;
942               break;
943             }
944
945           i++;
946         }
947
948       if(host->h_addr_list[i])
949         break;
950
951       sock_close(sock);
952     }
953 #endif /* !HAVE_GETADDRINFO */
954
955   xfree(srvlist);
956
957   if(!connected)
958     {
959       int err=errno;
960 #ifdef _WIN32
961       if(hostfound)
962         log_error("%s: Unable to connect: ec=%d\n",server,(int)WSAGetLastError());
963       else
964         log_error("%s: Host not found: ec=%d\n",server,(int)WSAGetLastError());
965 #else
966       if(hostfound)
967         log_error("%s: %s\n",server,strerror(err));
968       else
969         log_error("%s: Host not found\n",server);
970 #endif
971       if(sock!=-1)
972         sock_close(sock);
973       errno=err;
974       return -1;
975     }
976
977   return sock;
978 }
979
980
981 static int
982 write_server( int sock, const char *data, size_t length )
983 {
984     int nleft;
985
986     nleft = length;
987     while( nleft > 0 ) {
988 #ifdef _WIN32  
989         int nwritten;
990
991         nwritten = send (sock, data, nleft, 0);
992         if ( nwritten == SOCKET_ERROR ) {
993             log_info ("write failed: ec=%d\n", (int)WSAGetLastError ());
994             return G10ERR_NETWORK;
995         }
996 #else
997         int nwritten = write( sock, data, nleft );
998         if( nwritten == -1 ) {
999             if( errno == EINTR )
1000                 continue;
1001             if( errno == EAGAIN ) {
1002                 struct timeval tv;
1003
1004                 tv.tv_sec =  0;
1005                 tv.tv_usec = 50000;
1006                 select(0, NULL, NULL, NULL, &tv);
1007                 continue;
1008             }
1009             log_info("write failed: %s\n", strerror(errno));
1010             return G10ERR_NETWORK;
1011         }
1012 #endif
1013         nleft -=nwritten;
1014         data += nwritten;
1015     }
1016
1017     return 0;
1018 }
1019
1020 /**** Test code ****/
1021 #ifdef TEST
1022
1023 int
1024 main(int argc, char **argv)
1025 {
1026     int rc;
1027     PARSED_URI uri;
1028     URI_TUPLE r;
1029     struct http_context hd;
1030     int c;
1031
1032     log_set_name("http-test");
1033     if( argc == 1 ) {
1034         start_server();
1035         return 0;
1036     }
1037
1038     if( argc != 2 ) {
1039         fprintf(stderr,"usage: http-test uri\n");
1040         return 1;
1041     }
1042     argc--; argv++;
1043
1044     rc = parse_uri( &uri, *argv );
1045     if( rc ) {
1046         log_error("`%s': %s\n", *argv, g10_errstr(rc));
1047         release_parsed_uri( uri );
1048         return 1;
1049     }
1050
1051     printf("Scheme: %s\n", uri->scheme );
1052     printf("Host  : %s\n", uri->host );
1053     printf("Port  : %u\n", uri->port );
1054     printf("Path  : %s\n", uri->path );
1055     for( r=uri->params; r; r = r->next ) {
1056         printf("Params: %s=%s", r->name, r->value );
1057         if( strlen( r->value ) != r->valuelen )
1058             printf(" [real length=%d]", (int)r->valuelen );
1059         putchar('\n');
1060     }
1061     for( r=uri->query; r; r = r->next ) {
1062         printf("Query : %s=%s", r->name, r->value );
1063         if( strlen( r->value ) != r->valuelen )
1064             printf(" [real length=%d]", (int)r->valuelen );
1065         putchar('\n');
1066     }
1067     release_parsed_uri( uri ); uri = NULL;
1068
1069     rc = http_open_document( &hd, *argv, 0, NULL );
1070     if( rc ) {
1071         log_error("can't get `%s': %s\n", *argv, g10_errstr(rc));
1072         return 1;
1073     }
1074     log_info("open_http_document succeeded; status=%u\n", hd.status_code );
1075     while( (c=iobuf_get( hd.fp_read)) != -1 )
1076         putchar(c);
1077     http_close( &hd );
1078     return 0;
1079 }
1080 #endif /*TEST*/