Adjust to GNU coding standards
[gnupg.git] / util / http.c
1 /* http.c  -  HTTP protocol handler
2  * Copyright (C) 1999, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
3  *               2009, 2012 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                          struct http_srv *srv, 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                            struct http_srv *srv );
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            struct http_srv *srv, 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, srv, 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, struct http_srv *srv,
238                     STRLIST headers )
239 {
240     int rc;
241
242     rc = http_open(hd, HTTP_REQ_GET, document, auth, flags, proxy, srv,
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               struct http_srv *srv, 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, srv );
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, srv );
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                 struct http_srv *srv )
819 {
820   int sock = -1;
821   int srvcount = 0;
822   int connected = 0;
823   int hostfound = 0;
824   int chosen = -1;
825   struct srventry *srvlist = NULL;
826   int srvindex;
827
828 #ifdef _WIN32
829   unsigned long inaddr;
830
831   init_sockets();
832   /* Win32 gethostbyname doesn't handle IP addresses internally, so we
833      try inet_addr first on that platform only. */
834   if((inaddr=inet_addr(server))!=INADDR_NONE)
835     {
836       struct sockaddr_in addr;
837
838       memset(&addr,0,sizeof(addr));
839
840       if((sock=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET)
841         {
842           log_error("error creating socket: ec=%d\n",(int)WSAGetLastError());
843           return -1;
844         }
845
846       addr.sin_family=AF_INET; 
847       addr.sin_port=htons(port);
848       memcpy(&addr.sin_addr,&inaddr,sizeof(inaddr));      
849
850       if(connect(sock,(struct sockaddr *)&addr,sizeof(addr))==0)
851         return sock;
852       else
853         {
854           sock_close(sock);
855           return -1;
856         }
857     }
858 #endif
859
860 #ifdef USE_DNS_SRV
861   /* Do the SRV thing */
862   if(srv && srv->srvtag)
863     {
864       /* We're using SRV, so append the tags */
865       if(1+strlen(srv->srvtag)+6+strlen(server)+1<=MAXDNAME)
866         {
867           char srvname[MAXDNAME];
868
869           strcpy(srvname,"_");
870           strcat(srvname,srv->srvtag);
871           strcat(srvname,"._tcp.");
872           strcat(srvname,server);
873           srvcount=getsrv(srvname,&srvlist);
874         }
875     }
876 #endif
877
878   if(srvlist==NULL)
879     {
880       /* Either we're not using SRV, or the SRV lookup failed.  Make
881          up a fake SRV record. */
882       srvlist=calloc(1,sizeof(struct srventry));
883       if(!srvlist)
884         return -1;
885       srvlist->port=port;
886       strncpy(srvlist->target,server,MAXDNAME);
887       srvlist->target[MAXDNAME-1]='\0';
888       srvcount=1;
889     }
890
891 #ifdef HAVE_GETADDRINFO
892
893   for(srvindex=0;srvindex<srvcount;srvindex++)
894     {
895       struct addrinfo hints,*res,*ai;
896       char portstr[6];
897
898       sprintf(portstr,"%u",srvlist[srvindex].port);
899       memset(&hints,0,sizeof(hints));
900       hints.ai_socktype=SOCK_STREAM;
901       if(getaddrinfo(srvlist[srvindex].target,portstr,&hints,&res)==0)
902         hostfound=1;
903       else
904         continue;
905
906       for(ai=res;ai;ai=ai->ai_next)
907         {
908           if((sock=socket(ai->ai_family,ai->ai_socktype,ai->ai_protocol))==-1)
909             {
910               log_error("error creating socket: %s\n",strerror(errno));
911               freeaddrinfo(res);
912               return -1;
913             }
914
915           if(connect(sock,ai->ai_addr,ai->ai_addrlen)==0)
916             {
917               connected=1;
918               chosen = srvindex;
919               break;
920             }
921
922           sock_close(sock);
923         }
924
925       freeaddrinfo(res);
926
927       if(ai)
928         break;
929     }
930
931 #else /* !HAVE_GETADDRINFO */
932
933   for(srvindex=0; srvindex < srvcount; srvindex++)
934     {
935       int i=0;
936       struct hostent *host=NULL;
937       struct sockaddr_in addr;
938
939       memset(&addr,0,sizeof(addr));
940
941       if((host=gethostbyname(srvlist[srvindex].target))==NULL)
942         continue;
943
944       hostfound=1;
945
946       if((sock=socket(host->h_addrtype,SOCK_STREAM,0))==-1)
947         {
948           log_error("error creating socket: %s\n",strerror(errno));
949           return -1;
950         }
951
952       addr.sin_family=host->h_addrtype;
953       if(addr.sin_family!=AF_INET)
954         {
955           log_error("%s: unknown address family\n",srvlist[srvindex].target);
956           return -1;
957         }
958
959       addr.sin_port=htons(srvlist[srvindex].port);
960
961       /* Try all A records until one responds. */
962       while(host->h_addr_list[i])
963         {
964           if(host->h_length!=4)
965             {
966               log_error("%s: illegal address length\n",srvlist[srvindex].target);
967               return -1;
968             }
969
970           memcpy(&addr.sin_addr,host->h_addr_list[i],host->h_length);
971
972           if(connect(sock,(struct sockaddr *)&addr,sizeof(addr))==0)
973             {
974               connected=1;
975               chosen = srvindex;
976               break;
977             }
978
979           i++;
980         }
981
982       if(host->h_addr_list[i])
983         break;
984
985       sock_close(sock);
986     }
987 #endif /* !HAVE_GETADDRINFO */
988
989   if(chosen > -1 && srv)
990     {
991       srv->used_server = strdup (srvlist[chosen].target);
992       srv->used_port = srvlist[chosen].port;
993     }
994
995   free(srvlist);
996
997   if(!connected)
998     {
999       int err=errno;
1000 #ifdef _WIN32
1001       if(hostfound)
1002         log_error("%s: Unable to connect: ec=%d\n",server,(int)WSAGetLastError());
1003       else
1004         log_error("%s: Host not found: ec=%d\n",server,(int)WSAGetLastError());
1005 #else
1006       if(hostfound)
1007         log_error("%s: %s\n",server,strerror(err));
1008       else
1009         log_error("%s: Host not found\n",server);
1010 #endif
1011       if(sock!=-1)
1012         sock_close(sock);
1013       errno=err;
1014       return -1;
1015     }
1016
1017   return sock;
1018 }
1019
1020
1021 static int
1022 write_server( int sock, const char *data, size_t length )
1023 {
1024     int nleft;
1025
1026     nleft = length;
1027     while( nleft > 0 ) {
1028 #ifdef _WIN32  
1029         int nwritten;
1030
1031         nwritten = send (sock, data, nleft, 0);
1032         if ( nwritten == SOCKET_ERROR ) {
1033             log_info ("write failed: ec=%d\n", (int)WSAGetLastError ());
1034             return G10ERR_NETWORK;
1035         }
1036 #else
1037         int nwritten = write( sock, data, nleft );
1038         if( nwritten == -1 ) {
1039             if( errno == EINTR )
1040                 continue;
1041             if( errno == EAGAIN ) {
1042                 struct timeval tv;
1043
1044                 tv.tv_sec =  0;
1045                 tv.tv_usec = 50000;
1046                 select(0, NULL, NULL, NULL, &tv);
1047                 continue;
1048             }
1049             log_info("write failed: %s\n", strerror(errno));
1050             return G10ERR_NETWORK;
1051         }
1052 #endif
1053         nleft -=nwritten;
1054         data += nwritten;
1055     }
1056
1057     return 0;
1058 }
1059
1060 /**** Test code ****/
1061 #ifdef TEST
1062
1063 int
1064 main(int argc, char **argv)
1065 {
1066     int rc;
1067     PARSED_URI uri;
1068     URI_TUPLE r;
1069     struct http_context hd;
1070     int c;
1071
1072     log_set_name("http-test");
1073     if( argc == 1 ) {
1074         start_server();
1075         return 0;
1076     }
1077
1078     if( argc != 2 ) {
1079         fprintf(stderr,"usage: http-test uri\n");
1080         return 1;
1081     }
1082     argc--; argv++;
1083
1084     rc = parse_uri( &uri, *argv );
1085     if( rc ) {
1086         log_error("`%s': %s\n", *argv, g10_errstr(rc));
1087         release_parsed_uri( uri );
1088         return 1;
1089     }
1090
1091     printf("Scheme: %s\n", uri->scheme );
1092     printf("Host  : %s\n", uri->host );
1093     printf("Port  : %u\n", uri->port );
1094     printf("Path  : %s\n", uri->path );
1095     for( r=uri->params; r; r = r->next ) {
1096         printf("Params: %s=%s", r->name, r->value );
1097         if( strlen( r->value ) != r->valuelen )
1098             printf(" [real length=%d]", (int)r->valuelen );
1099         putchar('\n');
1100     }
1101     for( r=uri->query; r; r = r->next ) {
1102         printf("Query : %s=%s", r->name, r->value );
1103         if( strlen( r->value ) != r->valuelen )
1104             printf(" [real length=%d]", (int)r->valuelen );
1105         putchar('\n');
1106     }
1107     release_parsed_uri( uri ); uri = NULL;
1108
1109     rc = http_open_document( &hd, *argv, NULL, 0, NULL, NULL, NULL );
1110     if( rc ) {
1111         log_error("can't get `%s': %s\n", *argv, g10_errstr(rc));
1112         return 1;
1113     }
1114     log_info("open_http_document succeeded; status=%u\n", hd.status_code );
1115     while( (c=iobuf_get( hd.fp_read)) != -1 )
1116         putchar(c);
1117     http_close( &hd );
1118     return 0;
1119 }
1120 #endif /*TEST*/