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