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