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