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