* http.c (do_parse_uri): Properly handle IPv6 literal addresses as per
[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=xmalloc_clear(sizeof(struct srventry));
860       srvlist->port=port;
861       strncpy(srvlist->target,server,MAXDNAME);
862       srvlist->target[MAXDNAME-1]='\0';
863       srvcount=1;
864     }
865
866 #ifdef HAVE_GETADDRINFO
867
868   for(srv=0;srv<srvcount;srv++)
869     {
870       struct addrinfo hints,*res,*ai;
871       char portstr[6];
872
873       sprintf(portstr,"%u",srvlist[srv].port);
874       memset(&hints,0,sizeof(hints));
875       hints.ai_socktype=SOCK_STREAM;
876       if(getaddrinfo(srvlist[srv].target,portstr,&hints,&res)==0)
877         hostfound=1;
878       else
879         continue;
880
881       for(ai=res;ai;ai=ai->ai_next)
882         {
883           if((sock=socket(ai->ai_family,ai->ai_socktype,ai->ai_protocol))==-1)
884             {
885               log_error("error creating socket: %s\n",strerror(errno));
886               freeaddrinfo(res);
887               return -1;
888             }
889
890           if(connect(sock,ai->ai_addr,ai->ai_addrlen)==0)
891             {
892               connected=1;
893               break;
894             }
895
896           sock_close(sock);
897         }
898
899       freeaddrinfo(res);
900
901       if(ai)
902         break;
903     }
904
905 #else /* !HAVE_GETADDRINFO */
906
907   for(srv=0;srv<srvcount;srv++)
908     {
909       int i=0;
910       struct hostent *host=NULL;
911       struct sockaddr_in addr;
912
913       memset(&addr,0,sizeof(addr));
914
915       if((host=gethostbyname(srvlist[srv].target))==NULL)
916         continue;
917
918       hostfound=1;
919
920       if((sock=socket(host->h_addrtype,SOCK_STREAM,0))==-1)
921         {
922           log_error("error creating socket: %s\n",strerror(errno));
923           return -1;
924         }
925
926       addr.sin_family=host->h_addrtype;
927       if(addr.sin_family!=AF_INET)
928         {
929           log_error("%s: unknown address family\n",srvlist[srv].target);
930           return -1;
931         }
932
933       addr.sin_port=htons(srvlist[srv].port);
934
935       /* Try all A records until one responds. */
936       while(host->h_addr_list[i])
937         {
938           if(host->h_length!=4)
939             {
940               log_error("%s: illegal address length\n",srvlist[srv].target);
941               return -1;
942             }
943
944           memcpy(&addr.sin_addr,host->h_addr_list[i],host->h_length);
945
946           if(connect(sock,(struct sockaddr *)&addr,sizeof(addr))==0)
947             {
948               connected=1;
949               break;
950             }
951
952           i++;
953         }
954
955       if(host->h_addr_list[i])
956         break;
957
958       sock_close(sock);
959     }
960 #endif /* !HAVE_GETADDRINFO */
961
962   xfree(srvlist);
963
964   if(!connected)
965     {
966       int err=errno;
967 #ifdef _WIN32
968       if(hostfound)
969         log_error("%s: Unable to connect: ec=%d\n",server,(int)WSAGetLastError());
970       else
971         log_error("%s: Host not found: ec=%d\n",server,(int)WSAGetLastError());
972 #else
973       if(hostfound)
974         log_error("%s: %s\n",server,strerror(err));
975       else
976         log_error("%s: Host not found\n",server);
977 #endif
978       if(sock!=-1)
979         sock_close(sock);
980       errno=err;
981       return -1;
982     }
983
984   return sock;
985 }
986
987
988 static int
989 write_server( int sock, const char *data, size_t length )
990 {
991     int nleft;
992
993     nleft = length;
994     while( nleft > 0 ) {
995 #ifdef _WIN32  
996         int nwritten;
997
998         nwritten = send (sock, data, nleft, 0);
999         if ( nwritten == SOCKET_ERROR ) {
1000             log_info ("write failed: ec=%d\n", (int)WSAGetLastError ());
1001             return G10ERR_NETWORK;
1002         }
1003 #else
1004         int nwritten = write( sock, data, nleft );
1005         if( nwritten == -1 ) {
1006             if( errno == EINTR )
1007                 continue;
1008             if( errno == EAGAIN ) {
1009                 struct timeval tv;
1010
1011                 tv.tv_sec =  0;
1012                 tv.tv_usec = 50000;
1013                 select(0, NULL, NULL, NULL, &tv);
1014                 continue;
1015             }
1016             log_info("write failed: %s\n", strerror(errno));
1017             return G10ERR_NETWORK;
1018         }
1019 #endif
1020         nleft -=nwritten;
1021         data += nwritten;
1022     }
1023
1024     return 0;
1025 }
1026
1027 /**** Test code ****/
1028 #ifdef TEST
1029
1030 int
1031 main(int argc, char **argv)
1032 {
1033     int rc;
1034     PARSED_URI uri;
1035     URI_TUPLE r;
1036     struct http_context hd;
1037     int c;
1038
1039     log_set_name("http-test");
1040     if( argc == 1 ) {
1041         start_server();
1042         return 0;
1043     }
1044
1045     if( argc != 2 ) {
1046         fprintf(stderr,"usage: http-test uri\n");
1047         return 1;
1048     }
1049     argc--; argv++;
1050
1051     rc = parse_uri( &uri, *argv );
1052     if( rc ) {
1053         log_error("`%s': %s\n", *argv, g10_errstr(rc));
1054         release_parsed_uri( uri );
1055         return 1;
1056     }
1057
1058     printf("Scheme: %s\n", uri->scheme );
1059     printf("Host  : %s\n", uri->host );
1060     printf("Port  : %u\n", uri->port );
1061     printf("Path  : %s\n", uri->path );
1062     for( r=uri->params; r; r = r->next ) {
1063         printf("Params: %s=%s", r->name, r->value );
1064         if( strlen( r->value ) != r->valuelen )
1065             printf(" [real length=%d]", (int)r->valuelen );
1066         putchar('\n');
1067     }
1068     for( r=uri->query; r; r = r->next ) {
1069         printf("Query : %s=%s", r->name, r->value );
1070         if( strlen( r->value ) != r->valuelen )
1071             printf(" [real length=%d]", (int)r->valuelen );
1072         putchar('\n');
1073     }
1074     release_parsed_uri( uri ); uri = NULL;
1075
1076     rc = http_open_document( &hd, *argv, NULL, 0, NULL );
1077     if( rc ) {
1078         log_error("can't get `%s': %s\n", *argv, g10_errstr(rc));
1079         return 1;
1080     }
1081     log_info("open_http_document succeeded; status=%u\n", hd.status_code );
1082     while( (c=iobuf_get( hd.fp_read)) != -1 )
1083         putchar(c);
1084     http_close( &hd );
1085     return 0;
1086 }
1087 #endif /*TEST*/