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