2f630ae589847ea5160f9658e90db51d450af7c4
[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[35];
603
604         if(port == 80 || (srv && srv->used_server))
605           *portstr = 0;
606         else
607           sprintf(portstr,":%u",port);
608
609         sprintf( request, "%s %s%s HTTP/1.0\r\nHost: %s%s\r\n%s",
610                  hd->req_type == HTTP_REQ_GET ? "GET" :
611                  hd->req_type == HTTP_REQ_HEAD? "HEAD":
612                  hd->req_type == HTTP_REQ_POST? "POST": "OOPS",
613                  *p == '/'? "":"/", p, server, portstr,
614                  authstr?authstr:"");
615       }
616
617     xfree(p);
618
619     rc = write_server( hd->sock, request, strlen(request) );
620
621     if(rc==0)
622       for(;headers;headers=headers->next)
623         {
624           rc = write_server( hd->sock, headers->d, strlen(headers->d) );
625           if(rc)
626             break;
627
628           rc = write_server( hd->sock, "\r\n", 2 );
629           if(rc)
630             break;
631         }
632
633     xfree( request );
634     xfree(proxy_authstr);
635     xfree(authstr);
636
637     return rc;
638 }
639
640
641 /****************
642  * Build the relative path from the parsed URI.
643  * Minimal implementation.
644  */
645 static byte*
646 build_rel_path( PARSED_URI uri )
647 {
648     URI_TUPLE r;
649     byte *rel_path, *p;
650     int n;
651
652     /* count the needed space */
653     n = insert_escapes( NULL, uri->path, "%;?&" );
654     /* todo: build params */
655     for( r=uri->query; r; r = r->next ) {
656         n++; /* '?'/'&' */
657         n += insert_escapes( NULL, r->name, "%;?&=" );
658         n++; /* '='*/
659         n += insert_escapes( NULL, r->value, "%;?&=" );
660     }
661     n++;
662
663     /* now  allocate and copy */
664     p = rel_path = xmalloc( n );
665     n = insert_escapes( p, uri->path, "%;?&" );
666     p += n;
667     /* todo: add params */
668     for( r=uri->query; r; r = r->next ) {
669         *p++ = r == uri->query? '?':'&';
670         n = insert_escapes( p, r->name, "%;?&=" );
671         p += n;
672         *p++ = '=';
673         /* todo: use valuelen */
674         n = insert_escapes( p, r->value, "%;?&=" );
675         p += n;
676     }
677     *p = 0;
678     return rel_path;
679 }
680
681
682
683 /***********************
684  * Parse the response from a server.
685  * Returns: errorcode and sets some fileds in the handle
686  */
687 static int
688 parse_response( HTTP_HD hd )
689 {
690     byte *line, *p, *p2;
691     unsigned maxlen, len;
692
693     /* Wait for the status line */
694     do {
695         maxlen = MAX_LINELEN;
696         len = iobuf_read_line( hd->fp_read, &hd->buffer,
697                                             &hd->buffer_size, &maxlen );
698         line = hd->buffer;
699         if( !maxlen )
700             return -1; /* line has been truncated */
701         if( !len )
702             return -1; /* eof */
703     } while( !*line  );
704
705     if( (p = strchr( line, '/')) )
706         *p++ = 0;
707     if( !p || strcmp( line, "HTTP" ) )
708         return 0; /* assume http 0.9 */
709
710     if( (p2 = strpbrk( p, " \t" ) ) ) {
711         *p2++ = 0;
712         p2 += strspn( p2, " \t" );
713     }
714     if( !p2 )
715         return 0; /* assume http 0.9 */
716     p = p2;
717     /* todo: add HTTP version number check here */
718     if( (p2 = strpbrk( p, " \t" ) ) )
719         *p2++ = 0;
720     if( !isdigit(p[0]) || !isdigit(p[1]) || !isdigit(p[2]) || p[3] ) {
721          /* malformed HTTP statuscode - assume HTTP 0.9 */
722         hd->is_http_0_9 = 1;
723         hd->status_code = 200;
724         return 0;
725     }
726     hd->status_code = atoi( p );
727
728     /* skip all the header lines and wait for the empty line */
729     do {
730         maxlen = MAX_LINELEN;
731         len = iobuf_read_line( hd->fp_read, &hd->buffer,
732                                &hd->buffer_size, &maxlen );
733         line = hd->buffer;
734         /* we ignore truncated lines */
735         if( !len )
736             return -1; /* eof */
737         /* time lineendings */
738         if( (*line == '\r' && line[1] == '\n') || *line == '\n' )
739             *line = 0;
740     } while( len && *line  );
741
742     return 0;
743 }
744
745 #ifdef TEST
746 static int
747 start_server(void)
748 {
749     struct sockaddr_in mya;
750     struct sockaddr_in peer;
751     int fd, client;
752     fd_set rfds;
753     int addrlen;
754     int i;
755
756     if( (fd=socket(AF_INET,SOCK_STREAM, 0)) == -1 ) {
757         log_error("socket() failed: %s\n", strerror(errno));
758         return -1;
759     }
760     i = 1;
761     if( setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (byte*)&i, sizeof(i) ) )
762         log_info("setsockopt(SO_REUSEADDR) failed: %s\n", strerror(errno) );
763
764     mya.sin_family=AF_INET;
765     memset(&mya.sin_addr, 0, sizeof(mya.sin_addr));
766     mya.sin_port=htons(11371);
767
768     if( bind( fd, (struct sockaddr *)&mya, sizeof(mya)) ) {
769         log_error("bind to port 11371 failed: %s\n", strerror(errno) );
770         sock_close( fd );
771         return -1;
772     }
773
774     if( listen( fd, 5 ) ) {
775         log_error("listen failed: %s\n", strerror(errno) );
776         sock_close( fd );
777         return -1;
778     }
779
780     for(;;) {
781         FD_ZERO(&rfds);
782         FD_SET( fd, &rfds );
783
784         if( select( fd+1, &rfds, NULL, NULL, NULL) <= 0 )
785             continue; /* ignore any errors */
786
787         if( !FD_ISSET( fd, &rfds ) )
788             continue;
789
790         addrlen = sizeof peer;
791         client = accept( fd, (struct sockaddr *)&peer, &addrlen);
792         if( client == -1 )
793             continue; /* oops */
794
795         log_info("connect from %s\n", inet_ntoa( peer.sin_addr ) );
796
797         fflush(stdout);
798         fflush(stderr);
799         if( !fork() ) {
800             int c;
801             FILE *fp;
802
803             fp = fdopen( client , "r" );
804             while( (c=getc(fp)) != EOF )
805                 putchar(c);
806             fclose(fp);
807             exit(0);
808         }
809         sock_close( client );
810     }
811
812
813     return 0;
814 }
815 #endif
816
817
818 static int
819 connect_server( const char *server, ushort port, unsigned int flags,
820                 struct http_srv *srv )
821 {
822   int sock = -1;
823   int srvcount = 0;
824   int connected = 0;
825   int hostfound = 0;
826   int chosen = -1;
827   int fakesrv = 0;
828   struct srventry *srvlist = NULL;
829   int srvindex;
830
831 #ifdef _WIN32
832   unsigned long inaddr;
833
834   init_sockets();
835   /* Win32 gethostbyname doesn't handle IP addresses internally, so we
836      try inet_addr first on that platform only. */
837   if((inaddr=inet_addr(server))!=INADDR_NONE)
838     {
839       struct sockaddr_in addr;
840
841       memset(&addr,0,sizeof(addr));
842
843       if((sock=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET)
844         {
845           log_error("error creating socket: ec=%d\n",(int)WSAGetLastError());
846           return -1;
847         }
848
849       addr.sin_family=AF_INET;
850       addr.sin_port=htons(port);
851       memcpy(&addr.sin_addr,&inaddr,sizeof(inaddr));
852
853       if(connect(sock,(struct sockaddr *)&addr,sizeof(addr))==0)
854         return sock;
855       else
856         {
857           sock_close(sock);
858           return -1;
859         }
860     }
861 #endif
862
863 #ifdef USE_DNS_SRV
864   /* Do the SRV thing */
865   if(srv && srv->srvtag)
866     {
867       /* We're using SRV, so append the tags */
868       if(1+strlen(srv->srvtag)+6+strlen(server)+1<=MAXDNAME)
869         {
870           char srvname[MAXDNAME];
871
872           strcpy(srvname,"_");
873           strcat(srvname,srv->srvtag);
874           strcat(srvname,"._tcp.");
875           strcat(srvname,server);
876           srvcount=getsrv(srvname,&srvlist);
877         }
878     }
879 #endif
880
881   if(srvlist==NULL)
882     {
883       /* Either we're not using SRV, or the SRV lookup failed.  Make
884          up a fake SRV record. */
885       srvlist=calloc(1,sizeof(struct srventry));
886       if(!srvlist)
887         return -1;
888       srvlist->port=port;
889       strncpy(srvlist->target,server,MAXDNAME);
890       srvlist->target[MAXDNAME-1]='\0';
891       srvcount = 1;
892       fakesrv = 1;
893     }
894
895 #ifdef HAVE_GETADDRINFO
896
897   for(srvindex=0;srvindex<srvcount;srvindex++)
898     {
899       struct addrinfo hints,*res,*ai;
900       char portstr[6];
901
902       sprintf(portstr,"%u",srvlist[srvindex].port);
903       memset(&hints,0,sizeof(hints));
904       hints.ai_socktype=SOCK_STREAM;
905       if(getaddrinfo(srvlist[srvindex].target,portstr,&hints,&res)==0)
906         hostfound=1;
907       else
908         continue;
909
910       for(ai=res;ai;ai=ai->ai_next)
911         {
912           if((sock=socket(ai->ai_family,ai->ai_socktype,ai->ai_protocol))==-1)
913             {
914               log_error("error creating socket: %s\n",strerror(errno));
915               freeaddrinfo(res);
916               return -1;
917             }
918
919           if(connect(sock,ai->ai_addr,ai->ai_addrlen)==0)
920             {
921               connected=1;
922               chosen = srvindex;
923               break;
924             }
925
926           sock_close(sock);
927         }
928
929       freeaddrinfo(res);
930
931       if(ai)
932         break;
933     }
934
935 #else /* !HAVE_GETADDRINFO */
936
937   for(srvindex=0; srvindex < srvcount; srvindex++)
938     {
939       int i=0;
940       struct hostent *host=NULL;
941       struct sockaddr_in addr;
942
943       memset(&addr,0,sizeof(addr));
944
945       if((host=gethostbyname(srvlist[srvindex].target))==NULL)
946         continue;
947
948       hostfound=1;
949
950       if((sock=socket(host->h_addrtype,SOCK_STREAM,0))==-1)
951         {
952           log_error("error creating socket: %s\n",strerror(errno));
953           return -1;
954         }
955
956       addr.sin_family=host->h_addrtype;
957       if(addr.sin_family!=AF_INET)
958         {
959           log_error("%s: unknown address family\n",srvlist[srvindex].target);
960           return -1;
961         }
962
963       addr.sin_port=htons(srvlist[srvindex].port);
964
965       /* Try all A records until one responds. */
966       while(host->h_addr_list[i])
967         {
968           if(host->h_length!=4)
969             {
970               log_error("%s: illegal address length\n",srvlist[srvindex].target);
971               return -1;
972             }
973
974           memcpy(&addr.sin_addr,host->h_addr_list[i],host->h_length);
975
976           if(connect(sock,(struct sockaddr *)&addr,sizeof(addr))==0)
977             {
978               connected=1;
979               chosen = srvindex;
980               break;
981             }
982
983           i++;
984         }
985
986       if(host->h_addr_list[i])
987         break;
988
989       sock_close(sock);
990     }
991 #endif /* !HAVE_GETADDRINFO */
992
993   if(!fakesrv && chosen > -1 && srv)
994     {
995       srv->used_server = strdup (srvlist[chosen].target);
996       srv->used_port = srvlist[chosen].port;
997     }
998
999   free(srvlist);
1000
1001   if(!connected)
1002     {
1003       int err=errno;
1004 #ifdef _WIN32
1005       if(hostfound)
1006         log_error("%s: Unable to connect: ec=%d\n",server,(int)WSAGetLastError());
1007       else
1008         log_error("%s: Host not found: ec=%d\n",server,(int)WSAGetLastError());
1009 #else
1010       if(hostfound)
1011         log_error("%s: %s\n",server,strerror(err));
1012       else
1013         log_error("%s: Host not found\n",server);
1014 #endif
1015       if(sock!=-1)
1016         sock_close(sock);
1017       errno=err;
1018       return -1;
1019     }
1020
1021   return sock;
1022 }
1023
1024
1025 static int
1026 write_server( int sock, const char *data, size_t length )
1027 {
1028     int nleft;
1029
1030     nleft = length;
1031     while( nleft > 0 ) {
1032 #ifdef _WIN32
1033         int nwritten;
1034
1035         nwritten = send (sock, data, nleft, 0);
1036         if ( nwritten == SOCKET_ERROR ) {
1037             log_info ("write failed: ec=%d\n", (int)WSAGetLastError ());
1038             return G10ERR_NETWORK;
1039         }
1040 #else
1041         int nwritten = write( sock, data, nleft );
1042         if( nwritten == -1 ) {
1043             if( errno == EINTR )
1044                 continue;
1045             if( errno == EAGAIN ) {
1046                 struct timeval tv;
1047
1048                 tv.tv_sec =  0;
1049                 tv.tv_usec = 50000;
1050                 select(0, NULL, NULL, NULL, &tv);
1051                 continue;
1052             }
1053             log_info("write failed: %s\n", strerror(errno));
1054             return G10ERR_NETWORK;
1055         }
1056 #endif
1057         nleft -=nwritten;
1058         data += nwritten;
1059     }
1060
1061     return 0;
1062 }
1063
1064 /**** Test code ****/
1065 #ifdef TEST
1066
1067 int
1068 main(int argc, char **argv)
1069 {
1070     int rc;
1071     PARSED_URI uri;
1072     URI_TUPLE r;
1073     struct http_context hd;
1074     int c;
1075
1076     log_set_name("http-test");
1077     if( argc == 1 ) {
1078         start_server();
1079         return 0;
1080     }
1081
1082     if( argc != 2 ) {
1083         fprintf(stderr,"usage: http-test uri\n");
1084         return 1;
1085     }
1086     argc--; argv++;
1087
1088     rc = parse_uri( &uri, *argv );
1089     if( rc ) {
1090         log_error("`%s': %s\n", *argv, g10_errstr(rc));
1091         release_parsed_uri( uri );
1092         return 1;
1093     }
1094
1095     printf("Scheme: %s\n", uri->scheme );
1096     printf("Host  : %s\n", uri->host );
1097     printf("Port  : %u\n", uri->port );
1098     printf("Path  : %s\n", uri->path );
1099     for( r=uri->params; r; r = r->next ) {
1100         printf("Params: %s=%s", r->name, r->value );
1101         if( strlen( r->value ) != r->valuelen )
1102             printf(" [real length=%d]", (int)r->valuelen );
1103         putchar('\n');
1104     }
1105     for( r=uri->query; r; r = r->next ) {
1106         printf("Query : %s=%s", r->name, r->value );
1107         if( strlen( r->value ) != r->valuelen )
1108             printf(" [real length=%d]", (int)r->valuelen );
1109         putchar('\n');
1110     }
1111     release_parsed_uri( uri ); uri = NULL;
1112
1113     rc = http_open_document( &hd, *argv, NULL, 0, NULL, NULL, NULL );
1114     if( rc ) {
1115         log_error("can't get `%s': %s\n", *argv, g10_errstr(rc));
1116         return 1;
1117     }
1118     log_info("open_http_document succeeded; status=%u\n", hd.status_code );
1119     while( (c=iobuf_get( hd.fp_read)) != -1 )
1120         putchar(c);
1121     http_close( &hd );
1122     return 0;
1123 }
1124 #endif /*TEST*/