* http.c (connect_server): free (rather than xfree) the result of
[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
347             /* Handle a host of [IP] so that [IP:V6]:port works */
348             if( *p == '[' && (p3=strchr( p, ']' )) )
349               {
350                 *p3++ = '\0';
351                 /* worst case, uri->host should have length 0, points to \0 */
352                 uri->host = p + 1;
353                 p = p3;
354               }
355             else
356               uri->host = p;
357
358             if( (p3=strchr( p, ':' )) )
359               {
360                 *p3++ = '\0';
361                 uri->port = atoi( p3 );
362               }
363
364             if( (n = remove_escapes( uri->host )) < 0 )
365                 return G10ERR_BAD_URI;
366             if( n != strlen( uri->host ) )
367                 return G10ERR_BAD_URI; /* hostname with a Nul in it */
368             p = p2 ? p2 : NULL;
369         }
370     } /* end global URI part */
371
372     /* parse the pathname part */
373     if( !p || !*p ) /* we don't have a path */
374         return 0; /* and this is okay */
375
376     /* todo: here we have to check params */
377
378     /* do we have a query part */
379     if( (p2 = strchr( p, '?' )) )
380         *p2++ = 0;
381
382     uri->path = p;
383     if( (n = remove_escapes( p )) < 0 )
384         return G10ERR_BAD_URI;
385     if( n != strlen( p ) )
386         return G10ERR_BAD_URI; /* path with a Nul in it */
387     p = p2 ? p2 : NULL;
388
389     if( !p || !*p ) /* we don't have a query string */
390         return 0;   /* okay */
391
392     /* now parse the query string */
393     tail = &uri->query;
394     for(;;) {
395         URI_TUPLE elem;
396
397         if( (p2 = strchr( p, '&' )) )
398             *p2++ = 0;
399         if( !(elem = parse_tuple( p )) )
400             return G10ERR_BAD_URI;
401         *tail = elem;
402         tail = &elem->next;
403
404         if( !p2 )
405            break; /* ready */
406         p = p2;
407     }
408
409     return 0;
410 }
411
412
413
414 /****************
415  * Remove all %xx escapes; this is done inplace.
416  * Returns: new length of the string.
417  */
418 static int
419 remove_escapes( byte *string )
420 {
421     int n = 0;
422     byte *p, *s;
423
424     for(p=s=string; *s ; s++ ) {
425         if( *s == '%' ) {
426             if( s[1] && s[2] && isxdigit(s[1]) && isxdigit(s[2]) ) {
427                 s++;
428                 *p  = *s >= '0' && *s <= '9' ? *s - '0' :
429                       *s >= 'A' && *s <= 'F' ? *s - 'A' + 10 : *s - 'a' + 10 ;
430                 *p <<= 4;
431                 s++;
432                 *p |= *s >= '0' && *s <= '9' ? *s - '0' :
433                       *s >= 'A' && *s <= 'F' ? *s - 'A' + 10 : *s - 'a' + 10 ;
434                 p++;
435                 n++;
436             }
437             else {
438                 *p++ = *s++;
439                 if( *s )
440                    *p++ = *s++;
441                 if( *s )
442                    *p++ = *s++;
443                 if( *s )
444                    *p = 0;
445                 return -1; /* bad URI */
446             }
447         }
448         else
449         {
450             *p++ = *s;
451             n++;
452         }
453     }
454     *p = 0; /* always keep a string terminator */
455     return n;
456 }
457
458
459 static int
460 insert_escapes( byte *buffer, const byte *string, const byte *special )
461 {
462     int n = 0;
463
464     for( ; *string; string++ ) {
465         if( strchr( VALID_URI_CHARS, *string )
466             && !strchr( special, *string ) )  {
467             if( buffer )
468                 *buffer++ = *string;
469             n++;
470         }
471         else {
472             if( buffer ) {
473                 sprintf( buffer, "%%%02X", *string );
474                 buffer += 3;
475             }
476             n += 3;
477         }
478     }
479     return n;
480 }
481
482
483 static URI_TUPLE
484 parse_tuple( byte *string )
485 {
486     byte *p = string;
487     byte *p2;
488     int n;
489     URI_TUPLE tuple;
490
491     if( (p2 = strchr( p, '=' )) )
492         *p2++ = 0;
493     if( (n = remove_escapes( p )) < 0 )
494         return NULL; /* bad URI */
495     if( n != strlen( p ) )
496        return NULL; /* name with a Nul in it */
497     tuple = xmalloc_clear( sizeof *tuple );
498     tuple->name = p;
499     if( !p2 )  {
500         /* we have only the name, so we assume an empty value string */
501         tuple->value = p + strlen(p);
502         tuple->valuelen = 0;
503     }
504     else { /* name and value */
505         if( (n = remove_escapes( p2 )) < 0 ) {
506             xfree( tuple );
507             return NULL; /* bad URI */
508         }
509         tuple->value = p2;
510         tuple->valuelen = n;
511     }
512     return tuple;
513 }
514
515
516 /****************
517  * Send a HTTP request to the server
518  * Returns 0 if the request was successful
519  */
520 static int
521 send_request( HTTP_HD hd, const char *auth, const char *proxy )
522 {
523     const byte *server;
524     byte *request, *p;
525     ushort port;
526     int rc;
527     char *proxy_authstr=NULL,*authstr=NULL;
528
529     server = *hd->uri->host? hd->uri->host : "localhost";
530     port   = hd->uri->port?  hd->uri->port : 80;
531
532     if(proxy && *proxy)
533       {
534         PARSED_URI uri;
535
536         rc = parse_uri( &uri, proxy );
537         if (rc)
538           {
539             log_error("invalid HTTP proxy (%s): %s\n",proxy,g10_errstr(rc));
540             release_parsed_uri( uri );
541             return G10ERR_NETWORK;
542           }
543         hd->sock = connect_server( *uri->host? uri->host : "localhost",
544                                    uri->port? uri->port : 80, 0, NULL );
545         if(uri->auth)
546           {
547             char *x;
548             remove_escapes(uri->auth);
549             x=make_radix64_string(uri->auth,strlen(uri->auth));
550             proxy_authstr=xmalloc(52+strlen(x));
551             sprintf(proxy_authstr,"Proxy-Authorization: Basic %s\r\n",x);
552             xfree(x);
553           }
554
555         release_parsed_uri( uri );
556       }
557     else
558       hd->sock = connect_server( server, port, hd->flags, hd->uri->scheme );
559
560     if(auth || hd->uri->auth)
561       {
562         char *x,*tempauth=NULL;
563
564         if(auth)
565           {
566             tempauth=xstrdup(auth);
567             remove_escapes(tempauth);
568           }
569         else if(hd->uri->auth)
570           remove_escapes(hd->uri->auth);
571
572         x=make_radix64_string(tempauth?tempauth:hd->uri->auth,
573                               strlen(tempauth?tempauth:hd->uri->auth));
574         authstr=xmalloc(52+strlen(x));
575         sprintf(authstr,"Authorization: Basic %s\r\n",x);
576         xfree(x);
577         xfree(tempauth);
578       }
579
580     if( hd->sock == -1 )
581         return G10ERR_NETWORK;
582
583     p = build_rel_path( hd->uri );
584
585     request=xmalloc(strlen(server)*2 + strlen(p)
586                     + (authstr?strlen(authstr):0)
587                     + (proxy_authstr?strlen(proxy_authstr):0) + 65);
588     if( proxy && *proxy )
589       sprintf( request, "%s http://%s:%hu%s%s HTTP/1.0\r\n%s%s",
590                hd->req_type == HTTP_REQ_GET ? "GET" :
591                hd->req_type == HTTP_REQ_HEAD? "HEAD":
592                hd->req_type == HTTP_REQ_POST? "POST": "OOPS",
593                server, port,  *p == '/'? "":"/", p,
594                authstr?authstr:"",proxy_authstr?proxy_authstr:"" );
595     else
596       {
597         char portstr[15];
598
599         if(port!=80)
600           sprintf(portstr,":%u",port);
601
602         sprintf( request, "%s %s%s HTTP/1.0\r\nHost: %s%s\r\n%s",
603                  hd->req_type == HTTP_REQ_GET ? "GET" :
604                  hd->req_type == HTTP_REQ_HEAD? "HEAD":
605                  hd->req_type == HTTP_REQ_POST? "POST": "OOPS",
606                  *p == '/'? "":"/", p, server, (port!=80)?portstr:"",
607                  authstr?authstr:"");
608       }
609
610     xfree(p);
611
612     rc = write_server( hd->sock, request, strlen(request) );
613     xfree( request );
614     xfree(proxy_authstr);
615     xfree(authstr);
616
617     return rc;
618 }
619
620
621 /****************
622  * Build the relative path from the parsed URI.
623  * Minimal implementation.
624  */
625 static byte*
626 build_rel_path( PARSED_URI uri )
627 {
628     URI_TUPLE r;
629     byte *rel_path, *p;
630     int n;
631
632     /* count the needed space */
633     n = insert_escapes( NULL, uri->path, "%;?&" );
634     /* todo: build params */
635     for( r=uri->query; r; r = r->next ) {
636         n++; /* '?'/'&' */
637         n += insert_escapes( NULL, r->name, "%;?&=" );
638         n++; /* '='*/
639         n += insert_escapes( NULL, r->value, "%;?&=" );
640     }
641     n++;
642
643     /* now  allocate and copy */
644     p = rel_path = xmalloc( n );
645     n = insert_escapes( p, uri->path, "%;?&" );
646     p += n;
647     /* todo: add params */
648     for( r=uri->query; r; r = r->next ) {
649         *p++ = r == uri->query? '?':'&';
650         n = insert_escapes( p, r->name, "%;?&=" );
651         p += n;
652         *p++ = '=';
653         /* todo: use valuelen */
654         n = insert_escapes( p, r->value, "%;?&=" );
655         p += n;
656     }
657     *p = 0;
658     return rel_path;
659 }
660
661
662
663 /***********************
664  * Parse the response from a server.
665  * Returns: errorcode and sets some fileds in the handle
666  */
667 static int
668 parse_response( HTTP_HD hd )
669 {
670     byte *line, *p, *p2;
671     unsigned maxlen, len;
672
673     /* Wait for the status line */
674     do {
675         maxlen = MAX_LINELEN;
676         len = iobuf_read_line( hd->fp_read, &hd->buffer,
677                                             &hd->buffer_size, &maxlen );
678         line = hd->buffer;
679         if( !maxlen )
680             return -1; /* line has been truncated */
681         if( !len )
682             return -1; /* eof */
683     } while( !*line  );
684
685     if( (p = strchr( line, '/')) )
686         *p++ = 0;
687     if( !p || strcmp( line, "HTTP" ) )
688         return 0; /* assume http 0.9 */
689
690     if( (p2 = strpbrk( p, " \t" ) ) ) {
691         *p2++ = 0;
692         p2 += strspn( p2, " \t" );
693     }
694     if( !p2 )
695         return 0; /* assume http 0.9 */
696     p = p2;
697     /* todo: add HTTP version number check here */
698     if( (p2 = strpbrk( p, " \t" ) ) )
699         *p2++ = 0;
700     if( !isdigit(p[0]) || !isdigit(p[1]) || !isdigit(p[2]) || p[3] ) {
701          /* malformed HTTP statuscode - assume HTTP 0.9 */
702         hd->is_http_0_9 = 1;
703         hd->status_code = 200;
704         return 0;
705     }
706     hd->status_code = atoi( p );
707
708     /* skip all the header lines and wait for the empty line */
709     do {
710         maxlen = MAX_LINELEN;
711         len = iobuf_read_line( hd->fp_read, &hd->buffer,
712                                &hd->buffer_size, &maxlen );
713         line = hd->buffer;
714         /* we ignore truncated lines */
715         if( !len )
716             return -1; /* eof */
717         /* time lineendings */
718         if( (*line == '\r' && line[1] == '\n') || *line == '\n' )
719             *line = 0;
720     } while( len && *line  );
721
722     return 0;
723 }
724
725 #ifdef TEST
726 static int
727 start_server(void)
728 {
729     struct sockaddr_in mya;
730     struct sockaddr_in peer;
731     int fd, client;
732     fd_set rfds;
733     int addrlen;
734     int i;
735
736     if( (fd=socket(AF_INET,SOCK_STREAM, 0)) == -1 ) {
737         log_error("socket() failed: %s\n", strerror(errno));
738         return -1;
739     }
740     i = 1;
741     if( setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (byte*)&i, sizeof(i) ) )
742         log_info("setsockopt(SO_REUSEADDR) failed: %s\n", strerror(errno) );
743
744     mya.sin_family=AF_INET;
745     memset(&mya.sin_addr, 0, sizeof(mya.sin_addr));
746     mya.sin_port=htons(11371);
747
748     if( bind( fd, (struct sockaddr *)&mya, sizeof(mya)) ) {
749         log_error("bind to port 11371 failed: %s\n", strerror(errno) );
750         sock_close( fd );
751         return -1;
752     }
753
754     if( listen( fd, 5 ) ) {
755         log_error("listen failed: %s\n", strerror(errno) );
756         sock_close( fd );
757         return -1;
758     }
759
760     for(;;) {
761         FD_ZERO(&rfds);
762         FD_SET( fd, &rfds );
763
764         if( select( fd+1, &rfds, NULL, NULL, NULL) <= 0 )
765             continue; /* ignore any errors */
766
767         if( !FD_ISSET( fd, &rfds ) )
768             continue;
769
770         addrlen = sizeof peer;
771         client = accept( fd, (struct sockaddr *)&peer, &addrlen);
772         if( client == -1 )
773             continue; /* oops */
774
775         log_info("connect from %s\n", inet_ntoa( peer.sin_addr ) );
776
777         fflush(stdout);
778         fflush(stderr);
779         if( !fork() ) {
780             int c;
781             FILE *fp;
782
783             fp = fdopen( client , "r" );
784             while( (c=getc(fp)) != EOF )
785                 putchar(c);
786             fclose(fp);
787             exit(0);
788         }
789         sock_close( client );
790     }
791
792
793     return 0;
794 }
795 #endif
796
797
798 static int
799 connect_server( const char *server, ushort port, unsigned int flags,
800                 const char *srvtag )
801 {
802   int sock=-1,srv,srvcount=0,connected=0,hostfound=0;
803   struct srventry *srvlist=NULL;
804
805 #ifdef _WIN32
806   unsigned long inaddr;
807
808   init_sockets();
809   /* Win32 gethostbyname doesn't handle IP addresses internally, so we
810      try inet_addr first on that platform only. */
811   if((inaddr=inet_addr(server))!=INADDR_NONE)
812     {
813       struct sockaddr_in addr;
814
815       memset(&addr,0,sizeof(addr));
816
817       if((sock=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET)
818         {
819           log_error("error creating socket: ec=%d\n",(int)WSAGetLastError());
820           return -1;
821         }
822
823       addr.sin_family=AF_INET; 
824       addr.sin_port=htons(port);
825       memcpy(&addr.sin_addr,&inaddr,sizeof(inaddr));      
826
827       if(connect(sock,(struct sockaddr *)&addr,sizeof(addr))==0)
828         return sock;
829       else
830         {
831           sock_close(sock);
832           return -1;
833         }
834     }
835 #endif
836
837 #ifdef USE_DNS_SRV
838   /* Do the SRV thing */
839   if(flags&HTTP_FLAG_TRY_SRV && srvtag)
840     {
841       /* We're using SRV, so append the tags */
842       if(1+strlen(srvtag)+6+strlen(server)+1<=MAXDNAME)
843         {
844           char srvname[MAXDNAME];
845
846           strcpy(srvname,"_");
847           strcat(srvname,srvtag);
848           strcat(srvname,"._tcp.");
849           strcat(srvname,server);
850           srvcount=getsrv(srvname,&srvlist);
851         }
852     }
853 #endif
854
855   if(srvlist==NULL)
856     {
857       /* Either we're not using SRV, or the SRV lookup failed.  Make
858          up a fake SRV record. */
859       srvlist=calloc(1,sizeof(struct srventry));
860       if(!srvlist)
861         return -1;
862       srvlist->port=port;
863       strncpy(srvlist->target,server,MAXDNAME);
864       srvlist->target[MAXDNAME-1]='\0';
865       srvcount=1;
866     }
867
868 #ifdef HAVE_GETADDRINFO
869
870   for(srv=0;srv<srvcount;srv++)
871     {
872       struct addrinfo hints,*res,*ai;
873       char portstr[6];
874
875       sprintf(portstr,"%u",srvlist[srv].port);
876       memset(&hints,0,sizeof(hints));
877       hints.ai_socktype=SOCK_STREAM;
878       if(getaddrinfo(srvlist[srv].target,portstr,&hints,&res)==0)
879         hostfound=1;
880       else
881         continue;
882
883       for(ai=res;ai;ai=ai->ai_next)
884         {
885           if((sock=socket(ai->ai_family,ai->ai_socktype,ai->ai_protocol))==-1)
886             {
887               log_error("error creating socket: %s\n",strerror(errno));
888               freeaddrinfo(res);
889               return -1;
890             }
891
892           if(connect(sock,ai->ai_addr,ai->ai_addrlen)==0)
893             {
894               connected=1;
895               break;
896             }
897
898           sock_close(sock);
899         }
900
901       freeaddrinfo(res);
902
903       if(ai)
904         break;
905     }
906
907 #else /* !HAVE_GETADDRINFO */
908
909   for(srv=0;srv<srvcount;srv++)
910     {
911       int i=0;
912       struct hostent *host=NULL;
913       struct sockaddr_in addr;
914
915       memset(&addr,0,sizeof(addr));
916
917       if((host=gethostbyname(srvlist[srv].target))==NULL)
918         continue;
919
920       hostfound=1;
921
922       if((sock=socket(host->h_addrtype,SOCK_STREAM,0))==-1)
923         {
924           log_error("error creating socket: %s\n",strerror(errno));
925           return -1;
926         }
927
928       addr.sin_family=host->h_addrtype;
929       if(addr.sin_family!=AF_INET)
930         {
931           log_error("%s: unknown address family\n",srvlist[srv].target);
932           return -1;
933         }
934
935       addr.sin_port=htons(srvlist[srv].port);
936
937       /* Try all A records until one responds. */
938       while(host->h_addr_list[i])
939         {
940           if(host->h_length!=4)
941             {
942               log_error("%s: illegal address length\n",srvlist[srv].target);
943               return -1;
944             }
945
946           memcpy(&addr.sin_addr,host->h_addr_list[i],host->h_length);
947
948           if(connect(sock,(struct sockaddr *)&addr,sizeof(addr))==0)
949             {
950               connected=1;
951               break;
952             }
953
954           i++;
955         }
956
957       if(host->h_addr_list[i])
958         break;
959
960       sock_close(sock);
961     }
962 #endif /* !HAVE_GETADDRINFO */
963
964   free(srvlist);
965
966   if(!connected)
967     {
968       int err=errno;
969 #ifdef _WIN32
970       if(hostfound)
971         log_error("%s: Unable to connect: ec=%d\n",server,(int)WSAGetLastError());
972       else
973         log_error("%s: Host not found: ec=%d\n",server,(int)WSAGetLastError());
974 #else
975       if(hostfound)
976         log_error("%s: %s\n",server,strerror(err));
977       else
978         log_error("%s: Host not found\n",server);
979 #endif
980       if(sock!=-1)
981         sock_close(sock);
982       errno=err;
983       return -1;
984     }
985
986   return sock;
987 }
988
989
990 static int
991 write_server( int sock, const char *data, size_t length )
992 {
993     int nleft;
994
995     nleft = length;
996     while( nleft > 0 ) {
997 #ifdef _WIN32  
998         int nwritten;
999
1000         nwritten = send (sock, data, nleft, 0);
1001         if ( nwritten == SOCKET_ERROR ) {
1002             log_info ("write failed: ec=%d\n", (int)WSAGetLastError ());
1003             return G10ERR_NETWORK;
1004         }
1005 #else
1006         int nwritten = write( sock, data, nleft );
1007         if( nwritten == -1 ) {
1008             if( errno == EINTR )
1009                 continue;
1010             if( errno == EAGAIN ) {
1011                 struct timeval tv;
1012
1013                 tv.tv_sec =  0;
1014                 tv.tv_usec = 50000;
1015                 select(0, NULL, NULL, NULL, &tv);
1016                 continue;
1017             }
1018             log_info("write failed: %s\n", strerror(errno));
1019             return G10ERR_NETWORK;
1020         }
1021 #endif
1022         nleft -=nwritten;
1023         data += nwritten;
1024     }
1025
1026     return 0;
1027 }
1028
1029 /**** Test code ****/
1030 #ifdef TEST
1031
1032 int
1033 main(int argc, char **argv)
1034 {
1035     int rc;
1036     PARSED_URI uri;
1037     URI_TUPLE r;
1038     struct http_context hd;
1039     int c;
1040
1041     log_set_name("http-test");
1042     if( argc == 1 ) {
1043         start_server();
1044         return 0;
1045     }
1046
1047     if( argc != 2 ) {
1048         fprintf(stderr,"usage: http-test uri\n");
1049         return 1;
1050     }
1051     argc--; argv++;
1052
1053     rc = parse_uri( &uri, *argv );
1054     if( rc ) {
1055         log_error("`%s': %s\n", *argv, g10_errstr(rc));
1056         release_parsed_uri( uri );
1057         return 1;
1058     }
1059
1060     printf("Scheme: %s\n", uri->scheme );
1061     printf("Host  : %s\n", uri->host );
1062     printf("Port  : %u\n", uri->port );
1063     printf("Path  : %s\n", uri->path );
1064     for( r=uri->params; r; r = r->next ) {
1065         printf("Params: %s=%s", r->name, r->value );
1066         if( strlen( r->value ) != r->valuelen )
1067             printf(" [real length=%d]", (int)r->valuelen );
1068         putchar('\n');
1069     }
1070     for( r=uri->query; r; r = r->next ) {
1071         printf("Query : %s=%s", r->name, r->value );
1072         if( strlen( r->value ) != r->valuelen )
1073             printf(" [real length=%d]", (int)r->valuelen );
1074         putchar('\n');
1075     }
1076     release_parsed_uri( uri ); uri = NULL;
1077
1078     rc = http_open_document( &hd, *argv, NULL, 0, NULL );
1079     if( rc ) {
1080         log_error("can't get `%s': %s\n", *argv, g10_errstr(rc));
1081         return 1;
1082     }
1083     log_info("open_http_document succeeded; status=%u\n", hd.status_code );
1084     while( (c=iobuf_get( hd.fp_read)) != -1 )
1085         putchar(c);
1086     http_close( &hd );
1087     return 0;
1088 }
1089 #endif /*TEST*/