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