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