* Makefile.am, http.c (start_server): Minor tweaks to get http-test
[gnupg.git] / util / http.c
1 /* http.c  -  HTTP protocol handler
2  * Copyright (C) 1999, 2001, 2002, 2003, 2004,
3  *               2005, 2009 Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <errno.h>
28
29 #ifdef _WIN32
30 #include <windows.h>
31 #else
32 #include <unistd.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/time.h>
36 #include <time.h>
37 #include <netinet/in.h>
38 #include <arpa/inet.h>
39 #include <netdb.h>
40 #endif
41
42 #include "util.h"
43 #include "iobuf.h"
44 #include "i18n.h"
45 #include "http.h"
46 #include "srv.h"
47
48 #ifdef _WIN32
49 #define sock_close(a)  closesocket(a)
50 #else
51 #define sock_close(a)  close(a)
52 #endif
53
54 #define MAX_LINELEN 20000  /* max. length of a HTTP line */
55 #define VALID_URI_CHARS "abcdefghijklmnopqrstuvwxyz"   \
56                         "ABCDEFGHIJKLMNOPQRSTUVWXYZ"   \
57                         "01234567890@"                 \
58                         "!\"#$%&'()*+,-./:;<=>?[\\]^_{|}~"
59
60 #ifndef EAGAIN
61 #define EAGAIN  EWOULDBLOCK
62 #endif
63
64 static int parse_uri( PARSED_URI *ret_uri, const char *uri );
65 static void release_parsed_uri( PARSED_URI uri );
66 static int do_parse_uri( PARSED_URI uri, int only_local_part );
67 static int remove_escapes( byte *string );
68 static int insert_escapes( byte *buffer, const byte *string,
69                                          const byte *special );
70 static URI_TUPLE parse_tuple( byte *string );
71 static int send_request( HTTP_HD hd, const char *auth, const char *proxy );
72 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 modified to do the
120    "=" padding.  Better to use a 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 = xmalloc( (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         *p++ = '=';
138     }
139     else if( len == 1 ) {
140         *p++ = bintoasc[(data[0] >> 2) & 077];
141         *p++ = bintoasc[(data[0] <<4)&060];
142         *p++ = '=';
143         *p++ = '=';
144     }
145     *p = 0;
146     return buffer;
147 }
148
149 int
150 http_open( HTTP_HD hd, HTTP_REQ_TYPE reqtype, const char *url,
151            char *auth, unsigned int flags, const char *proxy )
152 {
153     int rc;
154
155     if( !(reqtype == HTTP_REQ_GET || reqtype == HTTP_REQ_POST) )
156         return G10ERR_INV_ARG;
157
158     /* initialize the handle */
159     memset( hd, 0, sizeof *hd );
160     hd->sock = -1;
161     hd->initialized = 1;
162     hd->req_type = reqtype;
163     hd->flags = flags;
164
165     rc = parse_uri( &hd->uri, url );
166     if( !rc ) {
167         rc = send_request( hd, auth, proxy );
168         if( !rc ) {
169             hd->fp_write = iobuf_sockopen( hd->sock , "w" );
170             if( hd->fp_write )
171                 return 0;
172             rc = G10ERR_GENERAL;
173         }
174     }
175
176     if( !hd->fp_read && !hd->fp_write && hd->sock != -1 )
177         sock_close( hd->sock );
178     iobuf_close( hd->fp_read );
179     iobuf_close( hd->fp_write);
180     release_parsed_uri( hd->uri );
181     hd->initialized = 0;
182
183     return rc;
184 }
185
186
187 void
188 http_start_data( HTTP_HD hd )
189 {
190     iobuf_flush ( hd->fp_write );
191     if( !hd->in_data ) {
192         write_server (hd->sock, "\r\n", 2);
193         hd->in_data = 1;
194     }
195 }
196
197
198 int
199 http_wait_response( HTTP_HD hd, unsigned int *ret_status )
200 {
201     int rc;
202
203     http_start_data( hd ); /* make sure that we are in the data */
204
205 #if 0
206     hd->sock = dup( hd->sock ); 
207     if( hd->sock == -1 )
208         return G10ERR_GENERAL;
209 #endif
210     iobuf_ioctl (hd->fp_write, 1, 1, NULL); /* keep the socket open */
211     iobuf_close (hd->fp_write);
212     hd->fp_write = NULL;
213     /* We do not want the shutdown code anymore.  It used to be there
214        to support old versions of pksd.  These versions are anyway
215        unusable and the latest releases haven been fixed to properly
216        handle HTTP 1.0. */
217     /* if ( !(hd->flags & HTTP_FLAG_NO_SHUTDOWN) ) */
218     /*     shutdown( hd->sock, 1 ); */
219     hd->in_data = 0;
220
221     hd->fp_read = iobuf_sockopen( hd->sock , "r" );
222     if( !hd->fp_read )
223         return G10ERR_GENERAL;
224
225     rc = parse_response( hd );
226     if( !rc && ret_status )
227         *ret_status = hd->status_code;
228
229     return rc;
230 }
231
232
233 int
234 http_open_document( HTTP_HD hd, const char *document, char *auth,
235                     unsigned int flags, const char *proxy )
236 {
237     int rc;
238
239     rc = http_open(hd, HTTP_REQ_GET, document, auth, flags, proxy );
240     if( rc )
241         return rc;
242
243     rc = http_wait_response( hd, NULL );
244     if( rc )
245         http_close( hd );
246
247     return rc;
248 }
249
250
251 void
252 http_close( HTTP_HD hd )
253 {
254     if( !hd || !hd->initialized )
255         return;
256     if( !hd->fp_read && !hd->fp_write && hd->sock != -1 )
257         sock_close( hd->sock );
258     iobuf_close( hd->fp_read );
259     iobuf_close( hd->fp_write );
260     release_parsed_uri( hd->uri );
261     xfree( hd->buffer );
262     hd->initialized = 0;
263 }
264
265
266
267 /****************
268  * Parse an URI and put the result into the newly allocated ret_uri.
269  * The caller must always use release_parsed_uri to releases the
270  * resources (even on an error).
271  */
272 static int
273 parse_uri( PARSED_URI *ret_uri, const char *uri )
274 {
275    *ret_uri = xmalloc_clear( sizeof(**ret_uri) + strlen(uri) );
276    strcpy( (*ret_uri)->buffer, uri );
277    return do_parse_uri( *ret_uri, 0 );
278 }
279
280 static void
281 release_parsed_uri( PARSED_URI uri )
282 {
283     if( uri )
284     {
285         URI_TUPLE r, r2;
286
287         for( r = uri->query; r; r = r2 ) {
288             r2 = r->next;
289             xfree( r );
290         }
291         xfree( uri );
292     }
293 }
294
295 static int
296 do_parse_uri( PARSED_URI uri, int only_local_part )
297 {
298     URI_TUPLE *tail;
299     char *p, *p2, *p3;
300     int n;
301
302     p = uri->buffer;
303     n = strlen( uri->buffer );
304     /* initialize all fields to an empty string or an empty list */
305     uri->scheme = uri->host = uri->path = p + n;
306     uri->port = 0;
307     uri->params = uri->query = NULL;
308
309     /* a quick validity check */
310     if( strspn( p, VALID_URI_CHARS) != n )
311         return G10ERR_BAD_URI; /* invalid characters found */
312
313     if( !only_local_part ) {
314         /* find the scheme */
315         if( !(p2 = strchr( p, ':' ) ) || p2 == p )
316            return G10ERR_BAD_URI; /* No scheme */
317         *p2++ = 0;
318         strlwr( p );
319         uri->scheme = p;
320         if(strcmp(uri->scheme,"http")==0)
321           uri->port = 80;
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 = xmalloc_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             xfree( 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 *auth, const char *proxy )
511 {
512     const byte *server;
513     byte *request, *p;
514     ushort port;
515     int rc;
516     char *proxy_authstr=NULL,*authstr=NULL;
517
518     server = *hd->uri->host? hd->uri->host : "localhost";
519     port   = hd->uri->port?  hd->uri->port : 80;
520
521     if(proxy && *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(uri->auth)
535           {
536             char *x;
537             remove_escapes(uri->auth);
538             x=make_radix64_string(uri->auth,strlen(uri->auth));
539             proxy_authstr=xmalloc(52+strlen(x));
540             sprintf(proxy_authstr,"Proxy-Authorization: Basic %s\r\n",x);
541             xfree(x);
542           }
543
544         release_parsed_uri( uri );
545       }
546     else
547       hd->sock = connect_server( server, port, hd->flags, hd->uri->scheme );
548
549     if(auth || hd->uri->auth)
550       {
551         char *x,*tempauth=NULL;
552
553         if(auth)
554           {
555             tempauth=xstrdup(auth);
556             remove_escapes(tempauth);
557           }
558         else if(hd->uri->auth)
559           remove_escapes(hd->uri->auth);
560
561         x=make_radix64_string(tempauth?tempauth:hd->uri->auth,
562                               strlen(tempauth?tempauth:hd->uri->auth));
563         authstr=xmalloc(52+strlen(x));
564         sprintf(authstr,"Authorization: Basic %s\r\n",x);
565         xfree(x);
566         xfree(tempauth);
567       }
568
569     if( hd->sock == -1 )
570         return G10ERR_NETWORK;
571
572     p = build_rel_path( hd->uri );
573
574     request=xmalloc(strlen(server)*2 + strlen(p)
575                     + (authstr?strlen(authstr):0)
576                     + (proxy_authstr?strlen(proxy_authstr):0) + 65);
577     if( proxy && *proxy )
578       sprintf( request, "%s http://%s:%hu%s%s HTTP/1.0\r\n%s%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                server, port,  *p == '/'? "":"/", p,
583                authstr?authstr:"",proxy_authstr?proxy_authstr:"" );
584     else
585       {
586         char portstr[15];
587
588         if(port!=80)
589           sprintf(portstr,":%u",port);
590
591         sprintf( request, "%s %s%s HTTP/1.0\r\nHost: %s%s\r\n%s",
592                  hd->req_type == HTTP_REQ_GET ? "GET" :
593                  hd->req_type == HTTP_REQ_HEAD? "HEAD":
594                  hd->req_type == HTTP_REQ_POST? "POST": "OOPS",
595                  *p == '/'? "":"/", p, server, (port!=80)?portstr:"",
596                  authstr?authstr:"");
597       }
598
599     xfree(p);
600
601     rc = write_server( hd->sock, request, strlen(request) );
602     xfree( request );
603     xfree(proxy_authstr);
604     xfree(authstr);
605
606     return rc;
607 }
608
609
610 /****************
611  * Build the relative path from the parsed URI.
612  * Minimal implementation.
613  */
614 static byte*
615 build_rel_path( PARSED_URI uri )
616 {
617     URI_TUPLE r;
618     byte *rel_path, *p;
619     int n;
620
621     /* count the needed space */
622     n = insert_escapes( NULL, uri->path, "%;?&" );
623     /* todo: build params */
624     for( r=uri->query; r; r = r->next ) {
625         n++; /* '?'/'&' */
626         n += insert_escapes( NULL, r->name, "%;?&=" );
627         n++; /* '='*/
628         n += insert_escapes( NULL, r->value, "%;?&=" );
629     }
630     n++;
631
632     /* now  allocate and copy */
633     p = rel_path = xmalloc( n );
634     n = insert_escapes( p, uri->path, "%;?&" );
635     p += n;
636     /* todo: add params */
637     for( r=uri->query; r; r = r->next ) {
638         *p++ = r == uri->query? '?':'&';
639         n = insert_escapes( p, r->name, "%;?&=" );
640         p += n;
641         *p++ = '=';
642         /* todo: use valuelen */
643         n = insert_escapes( p, r->value, "%;?&=" );
644         p += n;
645     }
646     *p = 0;
647     return rel_path;
648 }
649
650
651
652 /***********************
653  * Parse the response from a server.
654  * Returns: errorcode and sets some fileds in the handle
655  */
656 static int
657 parse_response( HTTP_HD hd )
658 {
659     byte *line, *p, *p2;
660     unsigned maxlen, len;
661
662     /* Wait for the status line */
663     do {
664         maxlen = MAX_LINELEN;
665         len = iobuf_read_line( hd->fp_read, &hd->buffer,
666                                             &hd->buffer_size, &maxlen );
667         line = hd->buffer;
668         if( !maxlen )
669             return -1; /* line has been truncated */
670         if( !len )
671             return -1; /* eof */
672     } while( !*line  );
673
674     if( (p = strchr( line, '/')) )
675         *p++ = 0;
676     if( !p || strcmp( line, "HTTP" ) )
677         return 0; /* assume http 0.9 */
678
679     if( (p2 = strpbrk( p, " \t" ) ) ) {
680         *p2++ = 0;
681         p2 += strspn( p2, " \t" );
682     }
683     if( !p2 )
684         return 0; /* assume http 0.9 */
685     p = p2;
686     /* todo: add HTTP version number check here */
687     if( (p2 = strpbrk( p, " \t" ) ) )
688         *p2++ = 0;
689     if( !isdigit(p[0]) || !isdigit(p[1]) || !isdigit(p[2]) || p[3] ) {
690          /* malformed HTTP statuscode - assume HTTP 0.9 */
691         hd->is_http_0_9 = 1;
692         hd->status_code = 200;
693         return 0;
694     }
695     hd->status_code = atoi( p );
696
697     /* skip all the header lines and wait for the empty line */
698     do {
699         maxlen = MAX_LINELEN;
700         len = iobuf_read_line( hd->fp_read, &hd->buffer,
701                                &hd->buffer_size, &maxlen );
702         line = hd->buffer;
703         /* we ignore truncated lines */
704         if( !len )
705             return -1; /* eof */
706         /* time lineendings */
707         if( (*line == '\r' && line[1] == '\n') || *line == '\n' )
708             *line = 0;
709     } while( len && *line  );
710
711     return 0;
712 }
713
714 #ifdef TEST
715 static int
716 start_server(void)
717 {
718     struct sockaddr_in mya;
719     struct sockaddr_in peer;
720     int fd, client;
721     fd_set rfds;
722     int addrlen;
723     int i;
724
725     if( (fd=socket(AF_INET,SOCK_STREAM, 0)) == -1 ) {
726         log_error("socket() failed: %s\n", strerror(errno));
727         return -1;
728     }
729     i = 1;
730     if( setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (byte*)&i, sizeof(i) ) )
731         log_info("setsockopt(SO_REUSEADDR) failed: %s\n", strerror(errno) );
732
733     mya.sin_family=AF_INET;
734     memset(&mya.sin_addr, 0, sizeof(mya.sin_addr));
735     mya.sin_port=htons(11371);
736
737     if( bind( fd, (struct sockaddr *)&mya, sizeof(mya)) ) {
738         log_error("bind to port 11371 failed: %s\n", strerror(errno) );
739         sock_close( fd );
740         return -1;
741     }
742
743     if( listen( fd, 5 ) ) {
744         log_error("listen failed: %s\n", strerror(errno) );
745         sock_close( fd );
746         return -1;
747     }
748
749     for(;;) {
750         FD_ZERO(&rfds);
751         FD_SET( fd, &rfds );
752
753         if( select( fd+1, &rfds, NULL, NULL, NULL) <= 0 )
754             continue; /* ignore any errors */
755
756         if( !FD_ISSET( fd, &rfds ) )
757             continue;
758
759         addrlen = sizeof peer;
760         client = accept( fd, (struct sockaddr *)&peer, &addrlen);
761         if( client == -1 )
762             continue; /* oops */
763
764         log_info("connect from %s\n", inet_ntoa( peer.sin_addr ) );
765
766         fflush(stdout);
767         fflush(stderr);
768         if( !fork() ) {
769             int c;
770             FILE *fp;
771
772             fp = fdopen( client , "r" );
773             while( (c=getc(fp)) != EOF )
774                 putchar(c);
775             fclose(fp);
776             exit(0);
777         }
778         sock_close( client );
779     }
780
781
782     return 0;
783 }
784 #endif
785
786
787 static int
788 connect_server( const char *server, ushort port, unsigned int flags,
789                 const char *srvtag )
790 {
791   int sock=-1,srv,srvcount=0,connected=0,hostfound=0;
792   struct srventry *srvlist=NULL;
793
794 #ifdef _WIN32
795   unsigned long inaddr;
796
797   init_sockets();
798   /* Win32 gethostbyname doesn't handle IP addresses internally, so we
799      try inet_addr first on that platform only. */
800   if((inaddr=inet_addr(server))!=INADDR_NONE)
801     {
802       struct sockaddr_in addr;
803
804       memset(&addr,0,sizeof(addr));
805
806       if((sock=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET)
807         {
808           log_error("error creating socket: ec=%d\n",(int)WSAGetLastError());
809           return -1;
810         }
811
812       addr.sin_family=AF_INET; 
813       addr.sin_port=htons(port);
814       memcpy(&addr.sin_addr,&inaddr,sizeof(inaddr));      
815
816       if(connect(sock,(struct sockaddr *)&addr,sizeof(addr))==0)
817         return sock;
818       else
819         {
820           sock_close(sock);
821           return -1;
822         }
823     }
824 #endif
825
826 #ifdef USE_DNS_SRV
827   /* Do the SRV thing */
828   if(flags&HTTP_FLAG_TRY_SRV && srvtag)
829     {
830       /* We're using SRV, so append the tags */
831       if(1+strlen(srvtag)+6+strlen(server)+1<=MAXDNAME)
832         {
833           char srvname[MAXDNAME];
834
835           strcpy(srvname,"_");
836           strcat(srvname,srvtag);
837           strcat(srvname,"._tcp.");
838           strcat(srvname,server);
839           srvcount=getsrv(srvname,&srvlist);
840         }
841     }
842 #endif
843
844   if(srvlist==NULL)
845     {
846       /* Either we're not using SRV, or the SRV lookup failed.  Make
847          up a fake SRV record. */
848       srvlist=xmalloc_clear(sizeof(struct srventry));
849       srvlist->port=port;
850       strncpy(srvlist->target,server,MAXDNAME);
851       srvlist->target[MAXDNAME-1]='\0';
852       srvcount=1;
853     }
854
855 #ifdef HAVE_GETADDRINFO
856
857   for(srv=0;srv<srvcount;srv++)
858     {
859       struct addrinfo hints,*res,*ai;
860       char portstr[6];
861
862       sprintf(portstr,"%u",srvlist[srv].port);
863       memset(&hints,0,sizeof(hints));
864       hints.ai_socktype=SOCK_STREAM;
865       if(getaddrinfo(srvlist[srv].target,portstr,&hints,&res)==0)
866         hostfound=1;
867       else
868         continue;
869
870       for(ai=res;ai;ai=ai->ai_next)
871         {
872           if((sock=socket(ai->ai_family,ai->ai_socktype,ai->ai_protocol))==-1)
873             {
874               log_error("error creating socket: %s\n",strerror(errno));
875               freeaddrinfo(res);
876               return -1;
877             }
878
879           if(connect(sock,ai->ai_addr,ai->ai_addrlen)==0)
880             {
881               connected=1;
882               break;
883             }
884
885           sock_close(sock);
886         }
887
888       freeaddrinfo(res);
889
890       if(ai)
891         break;
892     }
893
894 #else /* !HAVE_GETADDRINFO */
895
896   for(srv=0;srv<srvcount;srv++)
897     {
898       int i=0;
899       struct hostent *host=NULL;
900       struct sockaddr_in addr;
901
902       memset(&addr,0,sizeof(addr));
903
904       if((host=gethostbyname(srvlist[srv].target))==NULL)
905         continue;
906
907       hostfound=1;
908
909       if((sock=socket(host->h_addrtype,SOCK_STREAM,0))==-1)
910         {
911           log_error("error creating socket: %s\n",strerror(errno));
912           return -1;
913         }
914
915       addr.sin_family=host->h_addrtype;
916       if(addr.sin_family!=AF_INET)
917         {
918           log_error("%s: unknown address family\n",srvlist[srv].target);
919           return -1;
920         }
921
922       addr.sin_port=htons(srvlist[srv].port);
923
924       /* Try all A records until one responds. */
925       while(host->h_addr_list[i])
926         {
927           if(host->h_length!=4)
928             {
929               log_error("%s: illegal address length\n",srvlist[srv].target);
930               return -1;
931             }
932
933           memcpy(&addr.sin_addr,host->h_addr_list[i],host->h_length);
934
935           if(connect(sock,(struct sockaddr *)&addr,sizeof(addr))==0)
936             {
937               connected=1;
938               break;
939             }
940
941           i++;
942         }
943
944       if(host->h_addr_list[i])
945         break;
946
947       sock_close(sock);
948     }
949 #endif /* !HAVE_GETADDRINFO */
950
951   xfree(srvlist);
952
953   if(!connected)
954     {
955       int err=errno;
956 #ifdef _WIN32
957       if(hostfound)
958         log_error("%s: Unable to connect: ec=%d\n",server,(int)WSAGetLastError());
959       else
960         log_error("%s: Host not found: ec=%d\n",server,(int)WSAGetLastError());
961 #else
962       if(hostfound)
963         log_error("%s: %s\n",server,strerror(err));
964       else
965         log_error("%s: Host not found\n",server);
966 #endif
967       if(sock!=-1)
968         sock_close(sock);
969       errno=err;
970       return -1;
971     }
972
973   return sock;
974 }
975
976
977 static int
978 write_server( int sock, const char *data, size_t length )
979 {
980     int nleft;
981
982     nleft = length;
983     while( nleft > 0 ) {
984 #ifdef _WIN32  
985         int nwritten;
986
987         nwritten = send (sock, data, nleft, 0);
988         if ( nwritten == SOCKET_ERROR ) {
989             log_info ("write failed: ec=%d\n", (int)WSAGetLastError ());
990             return G10ERR_NETWORK;
991         }
992 #else
993         int nwritten = write( sock, data, nleft );
994         if( nwritten == -1 ) {
995             if( errno == EINTR )
996                 continue;
997             if( errno == EAGAIN ) {
998                 struct timeval tv;
999
1000                 tv.tv_sec =  0;
1001                 tv.tv_usec = 50000;
1002                 select(0, NULL, NULL, NULL, &tv);
1003                 continue;
1004             }
1005             log_info("write failed: %s\n", strerror(errno));
1006             return G10ERR_NETWORK;
1007         }
1008 #endif
1009         nleft -=nwritten;
1010         data += nwritten;
1011     }
1012
1013     return 0;
1014 }
1015
1016 /**** Test code ****/
1017 #ifdef TEST
1018
1019 int
1020 main(int argc, char **argv)
1021 {
1022     int rc;
1023     PARSED_URI uri;
1024     URI_TUPLE r;
1025     struct http_context hd;
1026     int c;
1027
1028     log_set_name("http-test");
1029     if( argc == 1 ) {
1030         start_server();
1031         return 0;
1032     }
1033
1034     if( argc != 2 ) {
1035         fprintf(stderr,"usage: http-test uri\n");
1036         return 1;
1037     }
1038     argc--; argv++;
1039
1040     rc = parse_uri( &uri, *argv );
1041     if( rc ) {
1042         log_error("`%s': %s\n", *argv, g10_errstr(rc));
1043         release_parsed_uri( uri );
1044         return 1;
1045     }
1046
1047     printf("Scheme: %s\n", uri->scheme );
1048     printf("Host  : %s\n", uri->host );
1049     printf("Port  : %u\n", uri->port );
1050     printf("Path  : %s\n", uri->path );
1051     for( r=uri->params; r; r = r->next ) {
1052         printf("Params: %s=%s", r->name, r->value );
1053         if( strlen( r->value ) != r->valuelen )
1054             printf(" [real length=%d]", (int)r->valuelen );
1055         putchar('\n');
1056     }
1057     for( r=uri->query; r; r = r->next ) {
1058         printf("Query : %s=%s", r->name, r->value );
1059         if( strlen( r->value ) != r->valuelen )
1060             printf(" [real length=%d]", (int)r->valuelen );
1061         putchar('\n');
1062     }
1063     release_parsed_uri( uri ); uri = NULL;
1064
1065     rc = http_open_document( &hd, *argv, NULL, 0, NULL );
1066     if( rc ) {
1067         log_error("can't get `%s': %s\n", *argv, g10_errstr(rc));
1068         return 1;
1069     }
1070     log_info("open_http_document succeeded; status=%u\n", hd.status_code );
1071     while( (c=iobuf_get( hd.fp_read)) != -1 )
1072         putchar(c);
1073     http_close( &hd );
1074     return 0;
1075 }
1076 #endif /*TEST*/