Fix last commit
[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, srvindex, srvcount=0, connected=0, hostfound=0, chosen=-1;
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(srv && srv->srvtag)
858     {
859       /* We're using SRV, so append the tags */
860       if(1+strlen(srv->srvtag)+6+strlen(server)+1<=MAXDNAME)
861         {
862           char srvname[MAXDNAME];
863
864           strcpy(srvname,"_");
865           strcat(srvname,srv->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(srvindex=0;srvindex<srvcount;srvindex++)
889     {
890       struct addrinfo hints,*res,*ai;
891       char portstr[6];
892
893       sprintf(portstr,"%u",srvlist[srvindex].port);
894       memset(&hints,0,sizeof(hints));
895       hints.ai_socktype=SOCK_STREAM;
896       if(getaddrinfo(srvlist[srvindex].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               chosen = srvindex;
914               break;
915             }
916
917           sock_close(sock);
918         }
919
920       freeaddrinfo(res);
921
922       if(ai)
923         break;
924     }
925
926 #else /* !HAVE_GETADDRINFO */
927
928   for(srvindex=0; srvindex < srvcount; srvindex++)
929     {
930       int i=0;
931       struct hostent *host=NULL;
932       struct sockaddr_in addr;
933
934       memset(&addr,0,sizeof(addr));
935
936       if((host=gethostbyname(srvlist[srvindex].target))==NULL)
937         continue;
938
939       hostfound=1;
940
941       if((sock=socket(host->h_addrtype,SOCK_STREAM,0))==-1)
942         {
943           log_error("error creating socket: %s\n",strerror(errno));
944           return -1;
945         }
946
947       addr.sin_family=host->h_addrtype;
948       if(addr.sin_family!=AF_INET)
949         {
950           log_error("%s: unknown address family\n",srvlist[srvindex].target);
951           return -1;
952         }
953
954       addr.sin_port=htons(srvlist[srvindex].port);
955
956       /* Try all A records until one responds. */
957       while(host->h_addr_list[i])
958         {
959           if(host->h_length!=4)
960             {
961               log_error("%s: illegal address length\n",srvlist[srvindex].target);
962               return -1;
963             }
964
965           memcpy(&addr.sin_addr,host->h_addr_list[i],host->h_length);
966
967           if(connect(sock,(struct sockaddr *)&addr,sizeof(addr))==0)
968             {
969               connected=1;
970               chosen = srvindex;
971               break;
972             }
973
974           i++;
975         }
976
977       if(host->h_addr_list[i])
978         break;
979
980       sock_close(sock);
981     }
982 #endif /* !HAVE_GETADDRINFO */
983
984   if(chosen>-1 && srv)
985     {
986       srv->used_server = strdup (srvlist[chosen].target);
987       srv->used_port = srvlist[chosen].port;
988     }
989
990   free(srvlist);
991
992   if(!connected)
993     {
994       int err=errno;
995 #ifdef _WIN32
996       if(hostfound)
997         log_error("%s: Unable to connect: ec=%d\n",server,(int)WSAGetLastError());
998       else
999         log_error("%s: Host not found: ec=%d\n",server,(int)WSAGetLastError());
1000 #else
1001       if(hostfound)
1002         log_error("%s: %s\n",server,strerror(err));
1003       else
1004         log_error("%s: Host not found\n",server);
1005 #endif
1006       if(sock!=-1)
1007         sock_close(sock);
1008       errno=err;
1009       return -1;
1010     }
1011
1012   return sock;
1013 }
1014
1015
1016 static int
1017 write_server( int sock, const char *data, size_t length )
1018 {
1019     int nleft;
1020
1021     nleft = length;
1022     while( nleft > 0 ) {
1023 #ifdef _WIN32  
1024         int nwritten;
1025
1026         nwritten = send (sock, data, nleft, 0);
1027         if ( nwritten == SOCKET_ERROR ) {
1028             log_info ("write failed: ec=%d\n", (int)WSAGetLastError ());
1029             return G10ERR_NETWORK;
1030         }
1031 #else
1032         int nwritten = write( sock, data, nleft );
1033         if( nwritten == -1 ) {
1034             if( errno == EINTR )
1035                 continue;
1036             if( errno == EAGAIN ) {
1037                 struct timeval tv;
1038
1039                 tv.tv_sec =  0;
1040                 tv.tv_usec = 50000;
1041                 select(0, NULL, NULL, NULL, &tv);
1042                 continue;
1043             }
1044             log_info("write failed: %s\n", strerror(errno));
1045             return G10ERR_NETWORK;
1046         }
1047 #endif
1048         nleft -=nwritten;
1049         data += nwritten;
1050     }
1051
1052     return 0;
1053 }
1054
1055 /**** Test code ****/
1056 #ifdef TEST
1057
1058 int
1059 main(int argc, char **argv)
1060 {
1061     int rc;
1062     PARSED_URI uri;
1063     URI_TUPLE r;
1064     struct http_context hd;
1065     int c;
1066
1067     log_set_name("http-test");
1068     if( argc == 1 ) {
1069         start_server();
1070         return 0;
1071     }
1072
1073     if( argc != 2 ) {
1074         fprintf(stderr,"usage: http-test uri\n");
1075         return 1;
1076     }
1077     argc--; argv++;
1078
1079     rc = parse_uri( &uri, *argv );
1080     if( rc ) {
1081         log_error("`%s': %s\n", *argv, g10_errstr(rc));
1082         release_parsed_uri( uri );
1083         return 1;
1084     }
1085
1086     printf("Scheme: %s\n", uri->scheme );
1087     printf("Host  : %s\n", uri->host );
1088     printf("Port  : %u\n", uri->port );
1089     printf("Path  : %s\n", uri->path );
1090     for( r=uri->params; r; r = r->next ) {
1091         printf("Params: %s=%s", r->name, r->value );
1092         if( strlen( r->value ) != r->valuelen )
1093             printf(" [real length=%d]", (int)r->valuelen );
1094         putchar('\n');
1095     }
1096     for( r=uri->query; r; r = r->next ) {
1097         printf("Query : %s=%s", r->name, r->value );
1098         if( strlen( r->value ) != r->valuelen )
1099             printf(" [real length=%d]", (int)r->valuelen );
1100         putchar('\n');
1101     }
1102     release_parsed_uri( uri ); uri = NULL;
1103
1104     rc = http_open_document( &hd, *argv, NULL, 0, NULL, NULL, NULL );
1105     if( rc ) {
1106         log_error("can't get `%s': %s\n", *argv, g10_errstr(rc));
1107         return 1;
1108     }
1109     log_info("open_http_document succeeded; status=%u\n", hd.status_code );
1110     while( (c=iobuf_get( hd.fp_read)) != -1 )
1111         putchar(c);
1112     http_close( &hd );
1113     return 0;
1114 }
1115 #endif /*TEST*/