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