5b67accc0f0629a9e550695448f1f87d2fe099e5
[gnupg.git] / common / http.c
1 /* http.c  -  HTTP protocol handler
2  * Copyright (C) 1999, 2001, 2002, 2003, 2004, 2006,
3  *               2009, 2012 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 /* Simple HTTP client implementation.  We try to keep the code as
22    self-contained as possible.  There are some contraints however:
23
24   - stpcpy is required
25   - fixme: list other requirements.
26
27
28   - With HTTP_USE_ESTREAM defined, all I/O is done through estream.
29   - With HTTP_USE_GNUTLS support for https is provided (this also
30     requires estream).
31   - With HTTP_NO_WSASTARTUP the socket initialization is not done
32     under Windows.  This is useful if the socket layer has already
33     been initialized elsewhere.  This also avoids the installation of
34     an exit handler to cleanup the socket layer.
35 */
36
37 #ifdef HAVE_CONFIG_H
38 # include <config.h>
39 #endif
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <stdarg.h>
43 #include <string.h>
44 #include <ctype.h>
45 #include <errno.h>
46 #include <unistd.h>
47
48 #ifdef HAVE_W32_SYSTEM
49 # include <windows.h>
50 #else /*!HAVE_W32_SYSTEM*/
51 # include <sys/types.h>
52 # include <sys/socket.h>
53 # include <sys/time.h>
54 # include <time.h>
55 # include <netinet/in.h>
56 # include <arpa/inet.h>
57 # include <netdb.h>
58 #endif /*!HAVE_W32_SYSTEM*/
59
60 #ifdef HTTP_USE_GNUTLS
61 # include <gnutls/gnutls.h>
62 /* For non-understandable reasons GNUTLS dropped the _t suffix from
63    all types. yes, ISO-C might be read as this but there are still
64    other name space conflicts and using _t is actually a Good
65    Thing. */
66 typedef gnutls_session gnutls_session_t;
67 typedef gnutls_transport_ptr gnutls_transport_ptr_t;
68 #endif /*HTTP_USE_GNUTLS*/
69
70 #ifdef TEST
71 #undef USE_DNS_SRV
72 #endif
73
74 #include "util.h"
75 #include "i18n.h"
76 #include "http.h"
77 #ifdef USE_DNS_SRV
78 #include "srv.h"
79 #else /*!USE_DNS_SRV*/
80 /* If we are not compiling with SRV record support we provide stub
81    data structures. */
82 #ifndef MAXDNAME
83 #define MAXDNAME 1025
84 #endif
85 struct srventry
86 {
87   unsigned short priority;
88   unsigned short weight;
89   unsigned short port;
90   int run_count;
91   char target[MAXDNAME];
92 };
93 #endif/*!USE_DNS_SRV*/
94
95
96 #ifdef HAVE_W32_SYSTEM
97 #define sock_close(a)  closesocket(a)
98 #else
99 #define sock_close(a)  close(a)
100 #endif
101
102 #ifndef EAGAIN
103 #define EAGAIN  EWOULDBLOCK
104 #endif
105
106 #define HTTP_PROXY_ENV           "http_proxy"
107 #define MAX_LINELEN 20000  /* Max. length of a HTTP header line. */
108 #define VALID_URI_CHARS "abcdefghijklmnopqrstuvwxyz"   \
109                         "ABCDEFGHIJKLMNOPQRSTUVWXYZ"   \
110                         "01234567890@"                 \
111                         "!\"#$%&'()*+,-./:;<=>?[\\]^_{|}~"
112
113 /* Define a prefix to map stream functions to the estream library. */
114 #ifdef HTTP_USE_ESTREAM
115 #define P_ES(a)  es_ ## a
116 #else
117 #define P_ES(a)  a
118 #endif
119 #ifndef HTTP_USE_GNUTLS
120 typedef void * gnutls_session_t;
121 #endif
122 #if defined(HTTP_USE_GNUTLS) && !defined(HTTP_USE_ESTREAM)
123 #error Use of GNUTLS also requires support for Estream
124 #endif
125
126 static gpg_error_t do_parse_uri (parsed_uri_t uri, int only_local_part);
127 static int remove_escapes (char *string);
128 static int insert_escapes (char *buffer, const char *string,
129                            const char *special);
130 static uri_tuple_t parse_tuple (char *string);
131 static gpg_error_t send_request (http_t hd, const char *auth,const char *proxy,
132                                  struct http_srv *srv,strlist_t headers);
133 static char *build_rel_path (parsed_uri_t uri);
134 static gpg_error_t parse_response (http_t hd);
135
136 static int connect_server (const char *server, unsigned short port,
137                            unsigned int flags, struct http_srv *srv);
138 static gpg_error_t write_server (int sock, const char *data, size_t length);
139
140 #ifdef HTTP_USE_ESTREAM
141 static ssize_t cookie_read (void *cookie, void *buffer, size_t size);
142 static ssize_t cookie_write (void *cookie, const void *buffer, size_t size);
143 static int cookie_close (void *cookie);
144
145 static es_cookie_io_functions_t cookie_functions =
146   {
147     cookie_read,
148     cookie_write,
149     NULL,
150     cookie_close
151   };
152
153 struct cookie_s 
154 {
155   int fd;  /* File descriptor or -1 if already closed. */
156   gnutls_session_t tls_session;  /* TLS session context or NULL if not used. */
157   int keep_socket; /* Flag to communicate with teh close handler. */
158 };
159 typedef struct cookie_s *cookie_t;
160
161 #endif /*HTTP_USE_ESTREAM*/
162
163 #ifdef HTTP_USE_GNUTLS
164 static gpg_error_t (*tls_callback) (http_t, gnutls_session_t, int);
165 #endif /*HTTP_USE_GNUTLS*/
166
167
168 /* An object to save header lines. */
169 struct header_s
170 {
171   struct header_s *next;
172   char *value;    /* The value of the header (malloced).  */
173   char name[1];   /* The name of the header (canonicalized). */
174 };
175 typedef struct header_s *header_t;
176
177
178 /* Our handle context. */
179 struct http_context_s 
180 {
181   unsigned int status_code;
182   int sock;
183   int in_data;
184 #ifdef HTTP_USE_ESTREAM
185   estream_t fp_read;
186   estream_t fp_write;
187   void *write_cookie;
188 #else /*!HTTP_USE_ESTREAM*/
189   FILE *fp_read;
190   FILE *fp_write;
191 #endif /*!HTTP_USE_ESTREAM*/
192   void *tls_context;
193   int is_http_0_9;
194   parsed_uri_t uri;
195   http_req_t req_type;
196   char *buffer;          /* Line buffer. */
197   size_t buffer_size;
198   unsigned int flags;
199   header_t headers;      /* Received headers. */
200 };
201
202
203
204 \f
205 #if defined(HAVE_W32_SYSTEM) && !defined(HTTP_NO_WSASTARTUP)
206
207 #if GNUPG_MAJOR_VERSION == 1
208 #define REQ_WINSOCK_MAJOR  1
209 #define REQ_WINSOCK_MINOR  1
210 #else
211 #define REQ_WINSOCK_MAJOR  2
212 #define REQ_WINSOCK_MINOR  2
213 #endif
214
215
216 static void
217 deinit_sockets (void)
218 {
219   WSACleanup();
220 }
221
222 static void
223 init_sockets (void)
224 {
225   static int initialized;
226   static WSADATA wsdata;
227
228   if (initialized)
229     return;
230
231   if ( WSAStartup( MAKEWORD (REQ_WINSOCK_MINOR, REQ_WINSOCK_MAJOR), &wsdata ) ) 
232     {
233       log_error ("error initializing socket library: ec=%d\n", 
234                  (int)WSAGetLastError () );
235       return;
236     }
237   if ( LOBYTE(wsdata.wVersion) != REQ_WINSOCK_MAJOR  
238        || HIBYTE(wsdata.wVersion) != REQ_WINSOCK_MINOR ) 
239     {
240       log_error ("socket library version is %x.%x - but %d.%d needed\n",
241                  LOBYTE(wsdata.wVersion), HIBYTE(wsdata.wVersion),
242                  REQ_WINSOCK_MAJOR, REQ_WINSOCK_MINOR);
243       WSACleanup();
244       return;
245     }
246   atexit ( deinit_sockets );
247   initialized = 1;
248 }
249 #endif /*HAVE_W32_SYSTEM && !HTTP_NO_WSASTARTUP*/
250
251
252
253 /*
254  * Helper function to create an HTTP header with hex encoded data.  A
255  * new buffer is returned.  This buffer is the concatenation of the
256  * string PREFIX, the hex-encoded DATA of length LEN and the string
257  * SUFFIX.  On error NULL is returned and ERRNO set.
258  */
259 static char *
260 make_header_line (const char *prefix, const char *suffix,
261                    const void *data, size_t len )
262 {
263   static unsigned char bintoasc[] = 
264     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
265     "abcdefghijklmnopqrstuvwxyz"
266     "0123456789+/";
267   const unsigned int *s = data;
268   char *buffer, *p;
269
270   buffer = xtrymalloc (strlen (prefix) + (len+2)/3*4 + strlen (suffix) + 1);
271   if (!buffer)
272     return NULL;
273   p = stpcpy (buffer, prefix);
274   for ( ; len >= 3 ; len -= 3, s += 3 )
275     {
276       *p++ = bintoasc[(s[0] >> 2) & 077];
277       *p++ = bintoasc[(((s[0] <<4)&060)|((s[1] >> 4)&017))&077];
278       *p++ = bintoasc[(((s[1]<<2)&074)|((s[2]>>6)&03))&077];
279       *p++ = bintoasc[s[2]&077];
280     }
281   if ( len == 2 ) 
282     {
283       *p++ = bintoasc[(s[0] >> 2) & 077];
284       *p++ = bintoasc[(((s[0] <<4)&060)|((s[1] >> 4)&017))&077];
285       *p++ = bintoasc[((s[1]<<2)&074)];
286       *p++ = '=';
287     }
288   else if ( len == 1 )
289     {
290       *p++ = bintoasc[(s[0] >> 2) & 077];
291       *p++ = bintoasc[(s[0] <<4)&060];
292       *p++ = '=';
293       *p++ = '=';
294     }
295   strcpy (p, suffix);
296   return buffer;
297 }
298
299
300
301 \f
302 void
303 http_register_tls_callback ( gpg_error_t (*cb) (http_t, void *, int) )
304 {
305 #ifdef HTTP_USE_GNUTLS
306   tls_callback = (gpg_error_t (*) (http_t, gnutls_session_t, int))cb;
307 #else
308   (void)cb;
309 #endif  
310 }
311
312
313
314 /* Start a HTTP retrieval and return on success in R_HD a context
315    pointer for completing the the request and to wait for the
316    response. */
317 gpg_error_t
318 http_open (http_t *r_hd, http_req_t reqtype, const char *url, 
319            const char *auth, unsigned int flags, const char *proxy,
320            void *tls_context, struct http_srv *srv, strlist_t headers)
321 {
322   gpg_error_t err;
323   http_t hd;
324   
325   *r_hd = NULL;
326
327   if (!(reqtype == HTTP_REQ_GET || reqtype == HTTP_REQ_POST))
328     return gpg_error (GPG_ERR_INV_ARG);
329
330   /* Create the handle. */
331   hd = xtrycalloc (1, sizeof *hd);
332   if (!hd)
333     return gpg_error_from_syserror ();
334   hd->sock = -1;
335   hd->req_type = reqtype;
336   hd->flags = flags;
337   hd->tls_context = tls_context;
338
339   err = http_parse_uri (&hd->uri, url);
340   if (!err)
341     err = send_request (hd, auth, proxy, srv, headers);
342   
343   if (err)
344     {
345       if (!hd->fp_read && !hd->fp_write && hd->sock != -1)
346         sock_close (hd->sock);
347       if (hd->fp_read)
348         P_ES(fclose) (hd->fp_read);
349       if (hd->fp_write)
350         P_ES(fclose) (hd->fp_write);
351       http_release_parsed_uri (hd->uri);
352       xfree (hd);
353     }
354   else
355     *r_hd = hd;
356   return err;
357 }
358
359
360 void
361 http_start_data (http_t hd)
362 {
363   if (!hd->in_data)
364     {
365 #ifdef HTTP_USE_ESTREAM
366       es_fputs ("\r\n", hd->fp_write);
367       es_fflush (hd->fp_write);
368 #else
369       fflush (hd->fp_write);
370       write_server (hd->sock, "\r\n", 2);
371 #endif
372       hd->in_data = 1;
373     }
374   else
375     P_ES(fflush) (hd->fp_write);
376 }
377
378
379 gpg_error_t
380 http_wait_response (http_t hd)
381 {
382   gpg_error_t err;
383
384   /* Make sure that we are in the data. */
385   http_start_data (hd); 
386
387   /* We dup the socket, to cope with the fact that fclose closes the
388      underlying socket. In TLS mode we don't do that because we can't
389      close the socket gnutls is working on; instead we make sure that
390      the fclose won't close the socket in this case. */
391 #ifdef HTTP_USE_ESTREAM
392   if (hd->write_cookie)
393     {
394       /* The write cookie is only set in the TLS case. */
395       cookie_t cookie = hd->write_cookie;
396       cookie->keep_socket = 1;
397     }
398   else
399 #endif /*HTTP_USE_ESTREAM*/
400     {
401 #ifdef HAVE_W32_SYSTEM
402       HANDLE handle = (HANDLE)hd->sock;
403       if (!DuplicateHandle (GetCurrentProcess(), handle,
404                             GetCurrentProcess(), &handle, 0,
405                             TRUE, DUPLICATE_SAME_ACCESS ))
406         return gpg_error_from_syserror ();
407       hd->sock = (int)handle;
408 #else
409       hd->sock = dup (hd->sock);
410 #endif
411       if (hd->sock == -1)
412         return gpg_error_from_syserror ();
413     }
414   P_ES(fclose) (hd->fp_write);
415   hd->fp_write = NULL;
416 #ifdef HTTP_USE_ESTREAM
417   hd->write_cookie = NULL;
418 #endif
419
420   if (!(hd->flags & HTTP_FLAG_NO_SHUTDOWN))
421     shutdown (hd->sock, 1);
422   hd->in_data = 0;
423
424 #ifdef HTTP_USE_ESTREAM
425   {
426     cookie_t cookie;
427
428     cookie = xtrycalloc (1, sizeof *cookie);
429     if (!cookie)
430       return gpg_error_from_syserror ();
431     cookie->fd = hd->sock;
432     if (hd->uri->use_tls)
433       cookie->tls_session = hd->tls_context;
434
435     hd->fp_read = es_fopencookie (cookie, "r", cookie_functions);
436     if (!hd->fp_read)
437       {
438         xfree (cookie);
439         return gpg_error_from_syserror ();
440       }
441   }
442 #else /*!HTTP_USE_ESTREAM*/
443   hd->fp_read = fdopen (hd->sock, "r");
444   if (!hd->fp_read)
445     return gpg_error_from_syserror ();
446 #endif /*!HTTP_USE_ESTREAM*/
447
448   err = parse_response (hd);
449   return err;
450 }
451
452
453 /* Convenience function to send a request and wait for the response.
454    Closes the handle on error.  If PROXY is not NULL, this value will
455    be used as an HTTP proxy and any enabled $http_proxy gets
456    ignored. */
457 gpg_error_t
458 http_open_document (http_t *r_hd, const char *document, 
459                     const char *auth, unsigned int flags, const char *proxy,
460                     void *tls_context, struct http_srv *srv,
461                     strlist_t headers)
462 {
463   gpg_error_t err;
464
465   err = http_open (r_hd, HTTP_REQ_GET, document, auth, flags,
466                    proxy, tls_context, srv, headers);
467   if (err)
468     return err;
469
470   err = http_wait_response (*r_hd);
471   if (err)
472     http_close (*r_hd, 0);
473
474   return err;
475 }
476
477
478 void
479 http_close (http_t hd, int keep_read_stream)
480 {
481   if (!hd)
482     return;
483   if (!hd->fp_read && !hd->fp_write && hd->sock != -1)
484     sock_close (hd->sock);
485   if (hd->fp_read && !keep_read_stream)
486     P_ES(fclose) (hd->fp_read);
487   if (hd->fp_write)
488     P_ES(fclose) (hd->fp_write);
489   http_release_parsed_uri (hd->uri);
490   while (hd->headers)
491     {
492       header_t tmp = hd->headers->next;
493       xfree (hd->headers->value);
494       xfree (hd->headers);
495       hd->headers = tmp;
496     }
497   xfree (hd->buffer);
498   xfree (hd);
499 }
500
501
502 #ifdef HTTP_USE_ESTREAM
503 estream_t
504 http_get_read_ptr (http_t hd)
505 {
506   return hd?hd->fp_read:NULL;
507 }
508 estream_t
509 http_get_write_ptr (http_t hd)
510 {
511   return hd?hd->fp_write:NULL;
512 }
513 #else /*!HTTP_USE_ESTREAM*/
514 FILE *
515 http_get_read_ptr (http_t hd)
516 {
517   return hd?hd->fp_read:NULL;
518 }
519 FILE *
520 http_get_write_ptr (http_t hd)
521 {
522   return hd?hd->fp_write:NULL;
523 }
524 #endif /*!HTTP_USE_ESTREAM*/
525 unsigned int
526 http_get_status_code (http_t hd)
527 {
528   return hd?hd->status_code:0;
529 }
530
531
532 \f
533 /*
534  * Parse an URI and put the result into the newly allocated RET_URI.
535  * The caller must always use release_parsed_uri() to releases the
536  * resources (even on error).
537  */
538 gpg_error_t
539 http_parse_uri (parsed_uri_t * ret_uri, const char *uri)
540 {
541   *ret_uri = xcalloc (1, sizeof **ret_uri + strlen (uri));
542   strcpy ((*ret_uri)->buffer, uri);
543   return do_parse_uri (*ret_uri, 0);
544 }
545
546 void
547 http_release_parsed_uri (parsed_uri_t uri)
548 {
549   if (uri)
550     {
551       uri_tuple_t r, r2;
552
553       for (r = uri->query; r; r = r2)
554         {
555           r2 = r->next;
556           xfree (r);
557         }
558       xfree (uri);
559     }
560 }
561
562
563 static gpg_error_t
564 do_parse_uri (parsed_uri_t uri, int only_local_part)
565 {
566   uri_tuple_t *tail;
567   char *p, *p2, *p3, *pp;
568   int n;
569
570   p = uri->buffer;
571   n = strlen (uri->buffer);
572
573   /* Initialize all fields to an empty string or an empty list. */
574   uri->scheme = uri->host = uri->path = p + n;
575   uri->port = 0;
576   uri->params = uri->query = NULL;
577   uri->use_tls = 0;
578
579   /* A quick validity check. */
580   if (strspn (p, VALID_URI_CHARS) != n)
581     return gpg_error (GPG_ERR_BAD_URI); /* Invalid characters found. */
582
583   if (!only_local_part)
584     {
585       /* Find the scheme. */
586       if (!(p2 = strchr (p, ':')) || p2 == p)
587         return gpg_error (GPG_ERR_BAD_URI); /* No scheme. */
588       *p2++ = 0;
589       for (pp=p; *pp; pp++)
590        *pp = tolower (*(unsigned char*)pp);
591       uri->scheme = p;
592       if (!strcmp (uri->scheme, "http"))
593         uri->port = 80;
594 #ifdef HTTP_USE_GNUTLS
595       else if (!strcmp (uri->scheme, "https"))
596         {
597           uri->port = 443;
598           uri->use_tls = 1;
599         }
600 #endif
601       else
602         return gpg_error (GPG_ERR_INV_URI); /* Unsupported scheme */
603
604       p = p2;
605
606       /* Find the hostname */
607       if (*p != '/')
608         return gpg_error (GPG_ERR_INV_URI); /* Does not start with a slash. */
609
610       p++;
611       if (*p == '/') /* There seems to be a hostname. */
612         { 
613           p++;
614           if ((p2 = strchr (p, '/')))
615             *p2++ = 0;
616
617           /* Check for username/password encoding */
618           if ((p3 = strchr (p, '@')))
619             {
620               uri->auth = p;
621               *p3++ = '\0';
622               p = p3;
623             }
624
625           for (pp=p; *pp; pp++)
626             *pp = tolower (*(unsigned char*)pp);
627
628           /* Handle an IPv6 literal */
629           if( *p == '[' && (p3=strchr( p, ']' )) )
630             {
631               *p3++ = '\0';
632               /* worst case, uri->host should have length 0, points to \0 */
633               uri->host = p + 1;
634               p = p3;
635             }
636           else
637             uri->host = p;
638
639           if ((p3 = strchr (p, ':')))
640             {
641               *p3++ = '\0';
642               uri->port = atoi (p3);
643             }
644
645           if ((n = remove_escapes (uri->host)) < 0)
646             return gpg_error (GPG_ERR_BAD_URI);
647           if (n != strlen (uri->host))
648             return gpg_error (GPG_ERR_BAD_URI); /* Hostname incudes a Nul. */
649           p = p2 ? p2 : NULL;
650         }
651     } /* End global URI part. */
652
653   /* Parse the pathname part */
654   if (!p || !*p)
655     return 0;  /* We don't have a path.  Okay. */
656
657   /* TODO: Here we have to check params. */
658
659   /* Do we have a query part? */
660   if ((p2 = strchr (p, '?')))
661     *p2++ = 0;
662
663   uri->path = p;
664   if ((n = remove_escapes (p)) < 0)
665     return gpg_error (GPG_ERR_BAD_URI);
666   if (n != strlen (p))
667     return gpg_error (GPG_ERR_BAD_URI); /* Path includes a Nul. */
668   p = p2 ? p2 : NULL;
669
670   if (!p || !*p)        
671     return 0; /* We don't have a query string.  Okay. */
672
673   /* Now parse the query string. */
674   tail = &uri->query;
675   for (;;)
676     {
677       uri_tuple_t elem;
678
679       if ((p2 = strchr (p, '&')))
680         *p2++ = 0;
681       if (!(elem = parse_tuple (p)))
682         return gpg_error (GPG_ERR_BAD_URI);
683       *tail = elem;
684       tail = &elem->next;
685
686       if (!p2)
687         break; /* Ready. */
688       p = p2;
689     }
690
691   return 0;
692 }
693
694
695 /*
696  * Remove all %xx escapes; this is done in-place.  Returns: New length
697  * of the string.
698  */
699 static int
700 remove_escapes (char *string)
701 {
702   int n = 0;
703   unsigned char *p, *s;
704
705   for (p = s = (unsigned char*)string; *s; s++)
706     {
707       if (*s == '%')
708         {
709           if (s[1] && s[2] && isxdigit (s[1]) && isxdigit (s[2]))
710             {
711               s++;
712               *p = *s >= '0' && *s <= '9' ? *s - '0' :
713                 *s >= 'A' && *s <= 'F' ? *s - 'A' + 10 : *s - 'a' + 10;
714               *p <<= 4;
715               s++;
716               *p |= *s >= '0' && *s <= '9' ? *s - '0' :
717                 *s >= 'A' && *s <= 'F' ? *s - 'A' + 10 : *s - 'a' + 10;
718               p++;
719               n++;
720             }
721           else
722             {
723               *p++ = *s++;
724               if (*s)
725                 *p++ = *s++;
726               if (*s)
727                 *p++ = *s++;
728               if (*s)
729                 *p = 0;
730               return -1; /* Bad URI. */
731             }
732         }
733       else
734         {
735           *p++ = *s;
736           n++;
737         }
738     }
739   *p = 0; /* Make sure to keep a string terminator. */
740   return n;
741 }
742
743
744 static int
745 insert_escapes (char *buffer, const char *string,
746                 const char *special)
747 {
748   const unsigned char *s = (const unsigned char*)string;
749   int n = 0;
750
751   for (; *s; s++)
752     {
753       if (strchr (VALID_URI_CHARS, *s) && !strchr (special, *s))
754         {
755           if (buffer)
756             *(unsigned char*)buffer++ = *s;
757           n++;
758         }
759       else
760         {
761           if (buffer)
762             {
763               sprintf (buffer, "%%%02X", *s);
764               buffer += 3;
765             }
766           n += 3;
767         }
768     }
769   return n;
770 }
771
772
773 /* Allocate a new string from STRING using standard HTTP escaping as
774    well as escaping of characters given in SPECIALS.  A common pattern
775    for SPECIALS is "%;?&=". However it depends on the needs, for
776    example "+" and "/: often needs to be escaped too.  Returns NULL on
777    failure and sets ERRNO. */
778 char *
779 http_escape_string (const char *string, const char *specials)
780 {
781   int n;
782   char *buf;
783
784   n = insert_escapes (NULL, string, specials);
785   buf = xtrymalloc (n+1);
786   if (buf)
787     {
788       insert_escapes (buf, string, specials);
789       buf[n] = 0;
790     }
791   return buf;
792 }
793
794
795
796 static uri_tuple_t
797 parse_tuple (char *string)
798 {
799   char *p = string;
800   char *p2;
801   int n;
802   uri_tuple_t tuple;
803
804   if ((p2 = strchr (p, '=')))
805     *p2++ = 0;
806   if ((n = remove_escapes (p)) < 0)
807     return NULL; /* Bad URI. */
808   if (n != strlen (p))
809     return NULL; /* Name with a Nul in it. */
810   tuple = xtrycalloc (1, sizeof *tuple);
811   if (!tuple)
812     return NULL; /* Out of core. */
813   tuple->name = p;
814   if (!p2) /* We have only the name, so we assume an empty value string. */
815     {
816       tuple->value = p + strlen (p);
817       tuple->valuelen = 0;
818       tuple->no_value = 1; /* Explicitly mark that we have seen no '='. */
819     }
820   else /* Name and value. */
821     {
822       if ((n = remove_escapes (p2)) < 0)
823         {
824           xfree (tuple);
825           return NULL; /* Bad URI. */
826         }
827       tuple->value = p2;
828       tuple->valuelen = n;
829     }
830   return tuple;
831 }
832
833
834 /*
835  * Send a HTTP request to the server
836  * Returns 0 if the request was successful
837  */
838 static gpg_error_t
839 send_request (http_t hd, const char *auth,
840               const char *proxy, struct http_srv *srv, strlist_t headers)
841 {
842   gnutls_session_t tls_session;
843   gpg_error_t err;
844   const char *server;
845   char *request, *p;
846   unsigned short port;
847   const char *http_proxy = NULL;
848   char *proxy_authstr = NULL;
849   char *authstr = NULL;
850   int save_errno;
851
852   tls_session = hd->tls_context;
853   if (hd->uri->use_tls && !tls_session)
854     {
855       log_error ("TLS requested but no GNUTLS context provided\n");
856       return gpg_error (GPG_ERR_INTERNAL);
857     }
858
859   server = *hd->uri->host ? hd->uri->host : "localhost";
860   port = hd->uri->port ? hd->uri->port : 80;
861
862   if ( (proxy && *proxy)
863        || ( (hd->flags & HTTP_FLAG_TRY_PROXY)
864             && (http_proxy = getenv (HTTP_PROXY_ENV)) 
865             && *http_proxy ))
866     {
867       parsed_uri_t uri;
868
869       if (proxy)
870         http_proxy = proxy;
871
872       err = http_parse_uri (&uri, http_proxy);
873       if (err)
874         {
875           log_error ("invalid HTTP proxy (%s): %s\n",
876                      http_proxy, gpg_strerror (err));
877           http_release_parsed_uri (uri);
878           return gpg_error (GPG_ERR_CONFIGURATION);
879
880         }
881
882       if (uri->auth)
883         {
884           remove_escapes (uri->auth);
885           proxy_authstr = make_header_line ("Proxy-Authorization: Basic ",
886                                             "\r\n",
887                                             uri->auth, strlen(uri->auth));
888           if (!proxy_authstr)
889             {
890               err = gpg_error_from_syserror ();
891               http_release_parsed_uri (uri);
892               return err;
893             }
894         }
895
896       hd->sock = connect_server (*uri->host ? uri->host : "localhost",
897                                  uri->port ? uri->port : 80,
898                                  hd->flags, srv);
899       save_errno = errno;
900       http_release_parsed_uri (uri);
901     }
902   else
903     {
904       hd->sock = connect_server (server, port, hd->flags, srv);
905       save_errno = errno;
906     }
907
908   if (hd->sock == -1)
909     {
910       xfree (proxy_authstr);
911       return (save_errno 
912               ? gpg_error_from_errno (save_errno)
913               : gpg_error (GPG_ERR_NOT_FOUND));
914     }
915
916 #ifdef HTTP_USE_GNUTLS
917   if (hd->uri->use_tls)
918     {
919       int rc;
920
921       gnutls_transport_set_ptr (tls_session, (gnutls_transport_ptr_t)hd->sock);
922       do
923         {
924           rc = gnutls_handshake (tls_session);
925         }
926       while (rc == GNUTLS_E_INTERRUPTED || rc == GNUTLS_E_AGAIN);
927       if (rc < 0)
928         {
929           log_info ("TLS handshake failed: %s\n", gnutls_strerror (rc));
930           xfree (proxy_authstr);
931           return gpg_error (GPG_ERR_NETWORK);
932         }
933
934       if (tls_callback)
935         {
936           err = tls_callback (hd, tls_session, 0);
937           if (err)
938             {
939               log_info ("TLS connection authentication failed: %s\n",
940                         gpg_strerror (err));
941               xfree (proxy_authstr);
942               return err;
943             }
944         }
945     }
946 #endif /*HTTP_USE_GNUTLS*/
947
948   if (auth || hd->uri->auth)
949     {
950       char *myauth;
951       
952       if (auth)
953         {
954           myauth = xtrystrdup (auth);
955           if (!myauth)
956             {
957               xfree (proxy_authstr);
958               return gpg_error_from_syserror ();
959             }
960           remove_escapes (myauth);
961         }
962       else
963         {
964           remove_escapes (hd->uri->auth);
965           myauth = hd->uri->auth;
966         }
967
968       authstr = make_header_line ("Authorization: Basic %s", "\r\n",
969                                   myauth, strlen (myauth));
970       if (auth)
971         xfree (myauth);
972
973       if (!authstr)
974         {
975           xfree (proxy_authstr);
976           return gpg_error_from_syserror ();
977         }
978     }
979   
980   p = build_rel_path (hd->uri);
981   if (!p)
982     return gpg_error_from_syserror ();
983
984   request = xtrymalloc (2 * strlen (server) 
985                         + strlen (p)
986                         + (authstr?strlen(authstr):0)
987                         + (proxy_authstr?strlen(proxy_authstr):0)
988                         + 100);
989   if (!request)
990     {
991       err = gpg_error_from_syserror ();
992       xfree (p);
993       xfree (authstr);
994       xfree (proxy_authstr);
995       return err;
996     }
997
998   if (http_proxy && *http_proxy)
999     {
1000       sprintf (request, "%s http://%s:%hu%s%s HTTP/1.0\r\n%s%s",
1001                hd->req_type == HTTP_REQ_GET ? "GET" :
1002                hd->req_type == HTTP_REQ_HEAD ? "HEAD" :
1003                hd->req_type == HTTP_REQ_POST ? "POST" : "OOPS",
1004                server, port, *p == '/' ? "" : "/", p,
1005                authstr ? authstr : "",
1006                proxy_authstr ? proxy_authstr : "");
1007     }
1008   else
1009     {
1010       char portstr[35];
1011         
1012       if (port == 80 || (srv && srv->used_server))
1013         *portstr = 0;
1014       else
1015         sprintf (portstr, ":%u", port);
1016
1017       sprintf (request, "%s %s%s HTTP/1.0\r\nHost: %s%s\r\n%s",
1018                hd->req_type == HTTP_REQ_GET ? "GET" :
1019                hd->req_type == HTTP_REQ_HEAD ? "HEAD" :
1020                hd->req_type == HTTP_REQ_POST ? "POST" : "OOPS",
1021                *p == '/' ? "" : "/", p, server, portstr,
1022                authstr? authstr:"");
1023     }
1024   xfree (p);
1025
1026
1027 #ifdef HTTP_USE_ESTREAM
1028   /* First setup estream so that we can write even the first line
1029      using estream.  This is also required for the sake of gnutls. */
1030   {
1031     cookie_t cookie;
1032
1033     cookie = xtrycalloc (1, sizeof *cookie);
1034     if (!cookie)
1035       {
1036         err = gpg_error_from_syserror ();
1037         goto leave;
1038       }
1039     cookie->fd = hd->sock;
1040     if (hd->uri->use_tls)
1041       {
1042         cookie->tls_session = tls_session;
1043         hd->write_cookie = cookie;
1044       }
1045
1046     hd->fp_write = es_fopencookie (cookie, "w", cookie_functions);
1047     if (!hd->fp_write)
1048       {
1049         xfree (cookie);
1050         err = gpg_error_from_syserror ();
1051       }
1052     else if (es_fputs (request, hd->fp_write) || es_fflush (hd->fp_write))
1053       err = gpg_error_from_syserror ();
1054     else
1055       err = 0;
1056
1057   if(err==0)
1058     for(;headers;headers=headers->next)
1059       {
1060         if ((es_fputs (headers->d, hd->fp_write) || es_fflush (hd->fp_write))
1061             || (es_fputs("\r\n",hd->fp_write) || es_fflush(hd->fp_write)))
1062           {
1063             err = gpg_error_from_syserror ();
1064             break;
1065           }
1066       }
1067   }
1068
1069  leave:
1070
1071 #else /*!HTTP_USE_ESTREAM*/
1072   /* We send out the start of the request through our own send
1073      function and only then assign a stdio stream.  This allows for
1074      better error reporting that through standard stdio means. */
1075   err = write_server (hd->sock, request, strlen (request));
1076
1077   if(err==0)
1078     for(;headers;headers=headers->next)
1079       {
1080         err = write_server( hd->sock, headers->d, strlen(headers->d) );
1081         if(err)
1082           break;
1083         err = write_server( hd->sock, "\r\n", 2 );
1084         if(err)
1085           break;
1086       }
1087
1088   if (!err)
1089     {
1090       hd->fp_write = fdopen (hd->sock, "w");
1091       if (!hd->fp_write)
1092         err = gpg_error_from_syserror ();
1093     }
1094
1095 #endif /*!HTTP_USE_ESTREAM*/
1096
1097   xfree (request);
1098   xfree (authstr);
1099   xfree (proxy_authstr);
1100
1101   return err;
1102 }
1103
1104
1105 /*
1106  * Build the relative path from the parsed URI.  Minimal
1107  * implementation.  May return NULL in case of memory failure; errno
1108  * is then set accordingly.
1109  */
1110 static char *
1111 build_rel_path (parsed_uri_t uri)
1112 {
1113   uri_tuple_t r;
1114   char *rel_path, *p;
1115   int n;
1116
1117   /* Count the needed space. */
1118   n = insert_escapes (NULL, uri->path, "%;?&");
1119   /* TODO: build params. */
1120   for (r = uri->query; r; r = r->next)
1121     {
1122       n++; /* '?'/'&' */
1123       n += insert_escapes (NULL, r->name, "%;?&=");
1124       if (!r->no_value)
1125         {
1126           n++; /* '=' */
1127           n += insert_escapes (NULL, r->value, "%;?&=");
1128         }
1129     }
1130   n++;
1131
1132   /* Now allocate and copy. */
1133   p = rel_path = xtrymalloc (n);
1134   if (!p)
1135     return NULL;
1136   n = insert_escapes (p, uri->path, "%;?&");
1137   p += n;
1138   /* TODO: add params. */
1139   for (r = uri->query; r; r = r->next)
1140     {
1141       *p++ = r == uri->query ? '?' : '&';
1142       n = insert_escapes (p, r->name, "%;?&=");
1143       p += n;
1144       if (!r->no_value)
1145         {
1146           *p++ = '=';
1147           /* TODO: Use valuelen. */
1148           n = insert_escapes (p, r->value, "%;?&=");
1149           p += n;
1150         }
1151     }
1152   *p = 0;
1153   return rel_path;
1154 }
1155
1156
1157
1158 /*
1159    Same as fgets() but if the buffer is too short a larger one will be
1160    allocated up to some limit *MAX_LENGTH.  A line is considered a
1161    byte stream ending in a LF.  Returns the length of the line. EOF is
1162    indicated by a line of length zero. The last LF may be missing due
1163    to an EOF.  If MAX_LENGTH is zero on return, the line has been
1164    truncated.  If the returned buffer is NULL, not enough memory was
1165    enable to increase it, the return value will also be 0 and some
1166    bytes might have been lost which should be no problem becuase
1167    out-of-memory is pretty fatal for most applications.
1168
1169    If a line has been truncated, the file pointer is internally moved
1170    forward to the end of the line.
1171
1172    Note: The returned buffer is allocated with enough extra space to
1173    append a CR,LF,Nul
1174  */
1175 static size_t
1176 my_read_line (
1177 #ifdef HTTP_USE_ESTREAM
1178               estream_t fp,
1179 #else
1180               FILE *fp,
1181 #endif
1182               char **addr_of_buffer,
1183               size_t *length_of_buffer, size_t *max_length)
1184 {
1185   int c;
1186   char *buffer = *addr_of_buffer;
1187   size_t length = *length_of_buffer;
1188   size_t nbytes = 0;
1189   size_t maxlen = *max_length;
1190   char *p;
1191
1192   if (!buffer) /* Must allocate a new buffer. */
1193     {           
1194       length = 256;
1195       buffer = xtrymalloc (length);
1196       *addr_of_buffer = buffer;
1197       if (!buffer)
1198         {
1199           *length_of_buffer = *max_length = 0;
1200           return 0;
1201         }
1202       *length_of_buffer = length;
1203     }
1204
1205   length -= 3; /* Reserve 3 bytes (cr,lf,eol). */
1206   p = buffer;
1207   while ((c = P_ES(getc) (fp)) != EOF)
1208     {
1209       if (nbytes == length) /* Increase the buffer. */
1210         {                       
1211           if (length > maxlen) /* Limit reached. */
1212             {
1213               /* Skip the rest of the line. */
1214               while (c != '\n' && (c = P_ES(getc) (fp)) != EOF)
1215                 ;
1216               *p++ = '\n'; /* Always append a LF (we reserved some space). */
1217               nbytes++;
1218               *max_length = 0; /* Indicate truncation */
1219               break; /*(the while loop)*/
1220             }
1221           length += 3; /* Adjust for the reserved bytes. */
1222           length += length < 1024 ? 256 : 1024;
1223           *addr_of_buffer = xtryrealloc (buffer, length);
1224           if (!*addr_of_buffer)
1225             {
1226               int save_errno = errno;
1227               xfree (buffer);
1228               *length_of_buffer = *max_length = 0;
1229               errno = save_errno;
1230               return 0;
1231             }
1232           buffer = *addr_of_buffer;
1233           *length_of_buffer = length;
1234           length -= 3; /* And re-adjust for the reservation. */
1235           p = buffer + nbytes;
1236         }
1237       *p++ = c;
1238       nbytes++;
1239       if (c == '\n')
1240         break;
1241     }
1242   *p = 0; /* Make sure the line is a string. */
1243
1244   return nbytes;
1245 }
1246
1247
1248 /* Transform a header name into a standard capitalized format; e.g.
1249    "Content-Type".  Conversion stops at the colon.  As usual we don't
1250    use the localized versions of ctype.h. */
1251 static void
1252 capitalize_header_name (char *name)
1253 {
1254   int first = 1;
1255
1256   for (; *name && *name != ':'; name++)
1257     {
1258       if (*name == '-')
1259         first = 1;
1260       else if (first)
1261         {
1262           if (*name >= 'a' && *name <= 'z')
1263             *name = *name - 'a' + 'A';
1264           first = 0;
1265         }
1266       else if (*name >= 'A' && *name <= 'Z')
1267         *name = *name - 'A' + 'a';
1268     }
1269 }
1270
1271
1272 /* Store an HTTP header line in LINE away.  Line continuation is
1273    supported as well as merging of headers with the same name. This
1274    function may modify LINE. */
1275 static gpg_error_t
1276 store_header (http_t hd, char *line)
1277 {
1278   size_t n;
1279   char *p, *value;
1280   header_t h;
1281
1282   n = strlen (line);
1283   if (n && line[n-1] == '\n')
1284     {
1285       line[--n] = 0;
1286       if (n && line[n-1] == '\r')
1287         line[--n] = 0;
1288     }
1289   if (!n)  /* we are never called to hit this. */
1290     return gpg_error (GPG_ERR_BUG);
1291   if (*line == ' ' || *line == '\t')
1292     {
1293       /* Continuation. This won't happen too often as it is not
1294          recommended.  We use a straightforward implementaion. */
1295       if (!hd->headers)
1296         return gpg_error (GPG_ERR_PROTOCOL_VIOLATION);
1297       n += strlen (hd->headers->value);
1298       p = xtrymalloc (n+1);
1299       if (!p)
1300         return gpg_error_from_syserror ();
1301       strcpy (stpcpy (p, hd->headers->value), line);
1302       xfree (hd->headers->value);
1303       hd->headers->value = p;
1304       return 0;
1305     }
1306
1307   capitalize_header_name (line);
1308   p = strchr (line, ':');
1309   if (!p)
1310     return gpg_error (GPG_ERR_PROTOCOL_VIOLATION);
1311   *p++ = 0;
1312   while (*p == ' ' || *p == '\t')
1313     p++;
1314   value = p;
1315   
1316   for (h=hd->headers; h; h = h->next)
1317     if ( !strcmp (h->name, line) )
1318       break;
1319   if (h)
1320     {
1321       /* We have already seen a line with that name.  Thus we assume
1322          it is a comma separated list and merge them.  */
1323       p = xtrymalloc (strlen (h->value) + 1 + strlen (value)+ 1);
1324       if (!p)
1325         return gpg_error_from_syserror ();
1326       strcpy (stpcpy (stpcpy (p, h->value), ","), value);
1327       xfree (h->value);
1328       h->value = p;
1329       return 0;
1330     }
1331
1332   /* Append a new header. */
1333   h = xtrymalloc (sizeof *h + strlen (line));
1334   if (!h)
1335     return gpg_error_from_syserror ();
1336   strcpy (h->name, line);
1337   h->value = xtrymalloc (strlen (value)+1);
1338   if (!h->value)
1339     {
1340       xfree (h);
1341       return gpg_error_from_syserror ();
1342     }
1343   strcpy (h->value, value);
1344   h->next = hd->headers;
1345   hd->headers = h;
1346
1347   return 0;
1348 }
1349
1350
1351 /* Return the header NAME from the last response.  The returned value
1352    is valid as along as HD has not been closed and no othe request has
1353    been send. If the header was not found, NULL is returned.  Name
1354    must be canonicalized, that is the first letter of each dash
1355    delimited part must be uppercase and all other letters lowercase.
1356    Note that the context must have been opened with the
1357    HTTP_FLAG_NEED_HEADER. */
1358 const char *
1359 http_get_header (http_t hd, const char *name)
1360 {
1361   header_t h;
1362
1363   for (h=hd->headers; h; h = h->next)
1364     if ( !strcmp (h->name, name) )
1365       return h->value;
1366   return NULL;
1367 }
1368
1369
1370
1371 /*
1372  * Parse the response from a server.
1373  * Returns: Errorcode and sets some files in the handle
1374  */
1375 static gpg_error_t
1376 parse_response (http_t hd)
1377 {
1378   char *line, *p, *p2;
1379   size_t maxlen, len;
1380
1381   /* Delete old header lines.  */
1382   while (hd->headers)
1383     {
1384       header_t tmp = hd->headers->next;
1385       xfree (hd->headers->value);
1386       xfree (hd->headers);
1387       hd->headers = tmp;
1388     }
1389
1390   /* Wait for the status line. */
1391   do
1392     {
1393       maxlen = MAX_LINELEN;
1394       len = my_read_line (hd->fp_read, &hd->buffer, &hd->buffer_size, &maxlen);
1395       line = hd->buffer;
1396       if (!line)
1397         return gpg_error_from_syserror (); /* Out of core. */
1398       if (!maxlen)
1399         return gpg_error (GPG_ERR_TRUNCATED); /* Line has been truncated. */
1400       if (!len)
1401         return gpg_error (GPG_ERR_EOF);
1402       if ( (hd->flags & HTTP_FLAG_LOG_RESP) )
1403         log_info ("RESP: `%.*s'\n",
1404                   (int)strlen(line)-(*line&&line[1]?2:0),line);
1405     }
1406   while (!*line);
1407
1408   if ((p = strchr (line, '/')))
1409     *p++ = 0;
1410   if (!p || strcmp (line, "HTTP"))
1411     return 0; /* Assume http 0.9. */
1412
1413   if ((p2 = strpbrk (p, " \t")))
1414     {
1415       *p2++ = 0;
1416       p2 += strspn (p2, " \t");
1417     }
1418   if (!p2)
1419     return 0; /* Also assume http 0.9. */
1420   p = p2;
1421   /* TODO: Add HTTP version number check. */
1422   if ((p2 = strpbrk (p, " \t")))
1423     *p2++ = 0;
1424   if (!isdigit ((unsigned int)p[0]) || !isdigit ((unsigned int)p[1])
1425       || !isdigit ((unsigned int)p[2]) || p[3])
1426     {
1427       /* Malformed HTTP status code - assume http 0.9. */
1428       hd->is_http_0_9 = 1;
1429       hd->status_code = 200;
1430       return 0;
1431     }
1432   hd->status_code = atoi (p);
1433
1434   /* Skip all the header lines and wait for the empty line. */
1435   do
1436     {
1437       maxlen = MAX_LINELEN;
1438       len = my_read_line (hd->fp_read, &hd->buffer, &hd->buffer_size, &maxlen);
1439       line = hd->buffer;
1440       if (!line)
1441         return gpg_error_from_syserror (); /* Out of core. */
1442       /* Note, that we can silently ignore truncated lines. */
1443       if (!len)
1444         return gpg_error (GPG_ERR_EOF);
1445       /* Trim line endings of empty lines. */
1446       if ((*line == '\r' && line[1] == '\n') || *line == '\n')
1447         *line = 0;
1448       if ( (hd->flags & HTTP_FLAG_LOG_RESP) )
1449         log_info ("RESP: `%.*s'\n",
1450                   (int)strlen(line)-(*line&&line[1]?2:0),line);
1451       if ( (hd->flags & HTTP_FLAG_NEED_HEADER) && *line )
1452         {
1453           gpg_error_t err = store_header (hd, line);
1454           if (err)
1455             return err;
1456         }
1457     }
1458   while (len && *line);
1459
1460   return 0;
1461 }
1462
1463 #if 0
1464 static int
1465 start_server ()
1466 {
1467   struct sockaddr_in mya;
1468   struct sockaddr_in peer;
1469   int fd, client;
1470   fd_set rfds;
1471   int addrlen;
1472   int i;
1473
1474   if ((fd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
1475     {
1476       log_error ("socket() failed: %s\n", strerror (errno));
1477       return -1;
1478     }
1479   i = 1;
1480   if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (byte *) & i, sizeof (i)))
1481     log_info ("setsockopt(SO_REUSEADDR) failed: %s\n", strerror (errno));
1482
1483   mya.sin_family = AF_INET;
1484   memset (&mya.sin_addr, 0, sizeof (mya.sin_addr));
1485   mya.sin_port = htons (11371);
1486
1487   if (bind (fd, (struct sockaddr *) &mya, sizeof (mya)))
1488     {
1489       log_error ("bind to port 11371 failed: %s\n", strerror (errno));
1490       sock_close (fd);
1491       return -1;
1492     }
1493
1494   if (listen (fd, 5))
1495     {
1496       log_error ("listen failed: %s\n", strerror (errno));
1497       sock_close (fd);
1498       return -1;
1499     }
1500
1501   for (;;)
1502     {
1503       FD_ZERO (&rfds);
1504       FD_SET (fd, &rfds);
1505
1506       if (select (fd + 1, &rfds, NULL, NULL, NULL) <= 0)
1507         continue;               /* ignore any errors */
1508
1509       if (!FD_ISSET (fd, &rfds))
1510         continue;
1511
1512       addrlen = sizeof peer;
1513       client = accept (fd, (struct sockaddr *) &peer, &addrlen);
1514       if (client == -1)
1515         continue;               /* oops */
1516
1517       log_info ("connect from %s\n", inet_ntoa (peer.sin_addr));
1518
1519       fflush (stdout);
1520       fflush (stderr);
1521       if (!fork ())
1522         {
1523           int c;
1524           FILE *fp;
1525
1526           fp = fdopen (client, "r");
1527           while ((c = getc (fp)) != EOF)
1528             putchar (c);
1529           fclose (fp);
1530           exit (0);
1531         }
1532       sock_close (client);
1533     }
1534
1535
1536   return 0;
1537 }
1538 #endif
1539
1540 /* Actually connect to a server.  Returns the file descriptor or -1 on
1541    error.  ERRNO is set on error. */
1542 static int
1543 connect_server (const char *server, unsigned short port,
1544                 unsigned int flags, struct http_srv *srv)
1545 {
1546   int sock = -1;
1547   int srvcount = 0, fakesrv = 0;
1548   int hostfound = 0;
1549   int srvindex, connected, chosen=-1;
1550   int last_errno = 0;
1551   struct srventry *serverlist = NULL;
1552
1553   /* Not currently using the flags */
1554   (void)flags;
1555
1556 #ifdef HAVE_W32_SYSTEM
1557   unsigned long inaddr;
1558
1559 #ifndef HTTP_NO_WSASTARTUP
1560   init_sockets ();
1561 #endif
1562   /* Win32 gethostbyname doesn't handle IP addresses internally, so we
1563      try inet_addr first on that platform only. */
1564   inaddr = inet_addr(server);
1565   if ( inaddr != INADDR_NONE )
1566     {
1567       struct sockaddr_in addr;
1568       
1569       memset(&addr,0,sizeof(addr));
1570       
1571       sock = socket(AF_INET,SOCK_STREAM,0);
1572       if ( sock==INVALID_SOCKET )
1573         {
1574           log_error("error creating socket: ec=%d\n",(int)WSAGetLastError());
1575           return -1;
1576         }
1577
1578       addr.sin_family = AF_INET; 
1579       addr.sin_port = htons(port);
1580       memcpy (&addr.sin_addr,&inaddr,sizeof(inaddr));      
1581
1582       if (!connect (sock,(struct sockaddr *)&addr,sizeof(addr)) )
1583         return sock;
1584       sock_close(sock);
1585       return -1;
1586     }
1587 #endif /*HAVE_W32_SYSTEM*/
1588
1589 #ifdef USE_DNS_SRV
1590   /* Do the SRV thing */
1591   if (srv && srv->srvtag)
1592     {
1593       /* We're using SRV, so append the tags. */
1594       if (1+strlen (srv->srvtag) + 6 + strlen (server) + 1 <= MAXDNAME)
1595         {
1596           char srvname[MAXDNAME];
1597
1598           stpcpy (stpcpy (stpcpy (stpcpy (srvname,"_"), srv->srvtag),
1599                            "._tcp."), server);
1600           srvcount = getsrv (srvname, &serverlist);
1601         }
1602     }
1603 #endif /*USE_DNS_SRV*/
1604
1605   if (!serverlist)
1606     {
1607       /* Either we're not using SRV, or the SRV lookup failed.  Make
1608          up a fake SRV record. */
1609       serverlist = xtrycalloc (1, sizeof *serverlist);
1610       if (!serverlist)
1611         return -1; /* Out of core.  */
1612       serverlist->port = port;
1613       strncpy (serverlist->target, server, MAXDNAME);
1614       serverlist->target[MAXDNAME-1] = '\0';
1615       srvcount = 1;
1616       fakesrv = 1;
1617     }
1618
1619 #ifdef HAVE_GETADDRINFO
1620   connected = 0;
1621   for (srvindex=0; srvindex < srvcount && !connected; srvindex++)
1622     {
1623       struct addrinfo hints, *res, *ai;
1624       char portstr[35];
1625
1626       sprintf (portstr, "%hu", serverlist[srvindex].port);
1627       memset (&hints, 0, sizeof (hints));
1628       hints.ai_socktype = SOCK_STREAM;
1629       if (getaddrinfo (serverlist[srvindex].target, portstr, &hints, &res))
1630         continue; /* Not found - try next one. */
1631       hostfound = 1;
1632
1633       for (ai = res; ai && !connected; ai = ai->ai_next)
1634         {
1635           if (sock != -1)
1636             sock_close (sock);
1637           sock = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol);
1638           if (sock == -1)
1639             {
1640               int save_errno = errno;
1641               log_error ("error creating socket: %s\n", strerror (errno));
1642               freeaddrinfo (res);
1643               xfree (serverlist);
1644               errno = save_errno;
1645               return -1;
1646             }
1647           
1648           if (connect (sock, ai->ai_addr, ai->ai_addrlen))
1649             last_errno = errno;
1650           else
1651             {
1652               connected = 1;
1653               chosen = srvindex;
1654             }
1655         }
1656       freeaddrinfo (res);
1657     }
1658 #else /* !HAVE_GETADDRINFO */
1659   connected = 0;
1660   for (srvindex=0; srvindex < srvcount && !connected; srvindex++)
1661     {
1662       int i;
1663       struct hostent *host = NULL;
1664       struct sockaddr_in addr;
1665
1666       /* Note: This code is not thread-safe.  */
1667
1668       memset (&addr, 0, sizeof (addr));
1669       host = gethostbyname (serverlist[srvindex].target);
1670       if (!host)
1671         continue;
1672       hostfound = 1;
1673
1674       if (sock != -1)
1675         sock_close (sock);
1676       sock = socket (host->h_addrtype, SOCK_STREAM, 0);
1677       if (sock == -1)
1678         {
1679           log_error (_("error creating socket: %s\n"), strerror (errno));
1680           xfree (serverlist);
1681           return -1;
1682         }
1683       
1684       addr.sin_family = host->h_addrtype;
1685       if (addr.sin_family != AF_INET)
1686         {
1687           log_error ("unknown address family for `%s'\n",
1688                      serverlist[srvindex].target);
1689           xfree (serverlist);
1690           return -1;
1691         }
1692       addr.sin_port = htons (serverlist[srvindex].port);
1693       if (host->h_length != 4)
1694         {
1695           log_error ("illegal address length for `%s'\n",
1696                      serverlist[srvindex].target);
1697           xfree (serverlist);
1698           return -1;
1699         }
1700
1701       /* Try all A records until one responds. */
1702       for (i = 0; host->h_addr_list[i] && !connected; i++)
1703         {
1704           memcpy (&addr.sin_addr, host->h_addr_list[i], host->h_length);
1705           if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)))
1706             last_errno = errno;
1707           else
1708             {
1709               connected = 1;
1710               chosen = srvindex;
1711               break;
1712             }
1713         }
1714     }
1715 #endif /* !HAVE_GETADDRINFO */
1716
1717   if(!fakesrv && chosen>-1 && srv)
1718     {
1719       srv->used_server = xstrdup (serverlist[chosen].target);
1720       srv->used_port = serverlist[chosen].port;
1721     }
1722
1723   xfree (serverlist);
1724
1725   if (!connected)
1726     {
1727 #ifdef HAVE_W32_SYSTEM
1728       log_error ("can't connect to `%s': %s%sec=%d\n",
1729                    server,
1730                    hostfound? "":_("host not found"),
1731                    hostfound? "":" - ", (int)WSAGetLastError());
1732 #else
1733       log_error ("can't connect to `%s': %s\n",
1734                  server,
1735                  hostfound? strerror (last_errno):"host not found");
1736 #endif
1737       if (sock != -1)
1738         sock_close (sock);
1739       errno = last_errno;
1740       return -1;
1741     }
1742   return sock;
1743 }
1744
1745
1746 static gpg_error_t
1747 write_server (int sock, const char *data, size_t length)
1748 {
1749   int nleft;
1750
1751   nleft = length;
1752   while (nleft > 0)
1753     {
1754 #ifdef HAVE_W32_SYSTEM
1755       int nwritten;
1756       
1757       nwritten = send (sock, data, nleft, 0);
1758       if ( nwritten == SOCKET_ERROR ) 
1759         {
1760           log_info ("network write failed: ec=%d\n", (int)WSAGetLastError ());
1761           return gpg_error (GPG_ERR_NETWORK);
1762         }
1763 #else /*!HAVE_W32_SYSTEM*/
1764       int nwritten = write (sock, data, nleft);
1765       if (nwritten == -1)
1766         {
1767           if (errno == EINTR)
1768             continue;
1769           if (errno == EAGAIN)
1770             {
1771               struct timeval tv;
1772
1773               tv.tv_sec = 0;
1774               tv.tv_usec = 50000;
1775               select (0, NULL, NULL, NULL, &tv);
1776               continue;
1777             }
1778           log_info ("network write failed: %s\n", strerror (errno));
1779           return gpg_error_from_syserror ();
1780         }
1781 #endif /*!HAVE_W32_SYSTEM*/
1782       nleft -= nwritten;
1783       data += nwritten;
1784     }
1785
1786   return 0;
1787 }
1788
1789
1790 \f
1791 #ifdef HTTP_USE_ESTREAM
1792 /* Read handler for estream.  */
1793 static ssize_t
1794 cookie_read (void *cookie, void *buffer, size_t size)
1795 {
1796   cookie_t c = cookie;
1797   int nread;
1798
1799 #ifdef HTTP_USE_GNUTLS
1800   if (c->tls_session)
1801     {
1802     again:
1803       nread = gnutls_record_recv (c->tls_session, buffer, size);
1804       if (nread < 0)
1805         {
1806           if (nread == GNUTLS_E_INTERRUPTED)
1807             goto again;
1808           if (nread == GNUTLS_E_AGAIN)
1809             {
1810               struct timeval tv;
1811               
1812               tv.tv_sec = 0;
1813               tv.tv_usec = 50000;
1814               select (0, NULL, NULL, NULL, &tv);
1815               goto again;
1816             }
1817           if (nread == GNUTLS_E_REHANDSHAKE)
1818             goto again; /* A client is allowed to just ignore this request. */
1819           log_info ("TLS network read failed: %s\n", gnutls_strerror (nread));
1820           errno = EIO;
1821           return -1;
1822         }
1823     }
1824   else
1825 #endif /*HTTP_USE_GNUTLS*/
1826     {
1827       do
1828         {
1829 #ifdef HAVE_W32_SYSTEM
1830           /* Under Windows we need to use recv for a socket.  */
1831           nread = recv (c->fd, buffer, size, 0);
1832 #else          
1833           nread = read (c->fd, buffer, size);
1834 #endif
1835         }
1836       while (nread == -1 && errno == EINTR);
1837     }
1838
1839   return nread;
1840 }
1841
1842 /* Write handler for estream.  */
1843 static ssize_t
1844 cookie_write (void *cookie, const void *buffer, size_t size)
1845 {
1846   cookie_t c = cookie;
1847   int nwritten = 0;
1848
1849 #ifdef HTTP_USE_GNUTLS
1850   if (c->tls_session)
1851     {
1852       int nleft = size;
1853       while (nleft > 0)
1854         {
1855           nwritten = gnutls_record_send (c->tls_session, buffer, nleft); 
1856           if (nwritten <= 0)
1857             {
1858               if (nwritten == GNUTLS_E_INTERRUPTED)
1859                 continue;
1860               if (nwritten == GNUTLS_E_AGAIN)
1861                 {
1862                   struct timeval tv;
1863                   
1864                   tv.tv_sec = 0;
1865                   tv.tv_usec = 50000;
1866                   select (0, NULL, NULL, NULL, &tv);
1867                   continue;
1868                 }
1869               log_info ("TLS network write failed: %s\n",
1870                         gnutls_strerror (nwritten));
1871               errno = EIO;
1872               return -1;
1873             }
1874           nleft -= nwritten;
1875           buffer += nwritten;
1876         }
1877     }
1878   else
1879 #endif /*HTTP_USE_GNUTLS*/
1880     {
1881       if ( write_server (c->fd, buffer, size) )
1882         {
1883           errno = EIO;
1884           nwritten = -1;
1885         }
1886       else
1887         nwritten = size;
1888     }
1889
1890   return nwritten;
1891 }
1892
1893 /* Close handler for estream.  */
1894 static int
1895 cookie_close (void *cookie)
1896 {
1897   cookie_t c = cookie;
1898
1899   if (!c)
1900     return 0;
1901
1902 #ifdef HTTP_USE_GNUTLS
1903   if (c->tls_session && !c->keep_socket)
1904     {
1905       gnutls_bye (c->tls_session, GNUTLS_SHUT_RDWR);
1906     }
1907 #endif /*HTTP_USE_GNUTLS*/
1908   if (c->fd != -1 && !c->keep_socket)
1909     sock_close (c->fd);
1910
1911   xfree (c);
1912   return 0;
1913 }
1914 #endif /*HTTP_USE_ESTREAM*/
1915
1916
1917
1918 \f
1919 /**** Test code ****/
1920 #ifdef TEST
1921
1922 static gpg_error_t
1923 verify_callback (http_t hd, void *tls_context, int reserved)
1924 {
1925   log_info ("verification of certificates skipped\n");
1926   return 0;
1927 }
1928
1929
1930
1931 /* static void */
1932 /* my_gnutls_log (int level, const char *text) */
1933 /* { */
1934 /*   fprintf (stderr, "gnutls:L%d: %s", level, text); */
1935 /* } */
1936
1937 int
1938 main (int argc, char **argv)
1939 {
1940   int rc;
1941   parsed_uri_t uri;
1942   uri_tuple_t r;
1943   http_t hd;
1944   int c;
1945   gnutls_session_t tls_session = NULL;
1946 #ifdef HTTP_USE_GNUTLS
1947   gnutls_certificate_credentials certcred;
1948   const int certprio[] = { GNUTLS_CRT_X509, 0 };
1949 #endif /*HTTP_USE_GNUTLS*/
1950   header_t hdr;
1951
1952 #ifdef HTTP_USE_ESTREAM
1953   es_init ();
1954 #endif
1955   log_set_prefix ("http-test", 1 | 4);
1956   if (argc == 1)
1957     {
1958       /*start_server (); */
1959       return 0;
1960     }
1961
1962   if (argc != 2)
1963     {
1964       fprintf (stderr, "usage: http-test uri\n");
1965       return 1;
1966     }
1967   argc--;
1968   argv++;
1969
1970 #ifdef HTTP_USE_GNUTLS
1971   rc = gnutls_global_init ();
1972   if (rc)
1973     log_error ("gnutls_global_init failed: %s\n", gnutls_strerror (rc));
1974   rc = gnutls_certificate_allocate_credentials (&certcred);
1975   if (rc)
1976     log_error ("gnutls_certificate_allocate_credentials failed: %s\n",
1977                gnutls_strerror (rc));
1978 /*   rc = gnutls_certificate_set_x509_trust_file */
1979 /*     (certcred, "ca.pem", GNUTLS_X509_FMT_PEM); */
1980 /*   if (rc) */
1981 /*     log_error ("gnutls_certificate_set_x509_trust_file failed: %s\n", */
1982 /*                gnutls_strerror (rc)); */
1983   rc = gnutls_init (&tls_session, GNUTLS_CLIENT);
1984   if (rc)
1985     log_error ("gnutls_init failed: %s\n", gnutls_strerror (rc));
1986   rc = gnutls_set_default_priority (tls_session);
1987   if (rc)
1988     log_error ("gnutls_set_default_priority failed: %s\n",
1989                gnutls_strerror (rc));
1990   rc = gnutls_certificate_type_set_priority (tls_session, certprio);
1991   if (rc)
1992     log_error ("gnutls_certificate_type_set_priority failed: %s\n",
1993                gnutls_strerror (rc));
1994   rc = gnutls_credentials_set (tls_session, GNUTLS_CRD_CERTIFICATE, certcred);
1995   if (rc)
1996     log_error ("gnutls_credentials_set failed: %s\n", gnutls_strerror (rc));
1997 /*   gnutls_global_set_log_function (my_gnutls_log); */
1998 /*   gnutls_global_set_log_level (4); */
1999
2000   http_register_tls_callback (verify_callback);
2001 #endif /*HTTP_USE_GNUTLS*/
2002
2003   rc = http_parse_uri (&uri, *argv);
2004   if (rc)
2005     {
2006       log_error ("`%s': %s\n", *argv, gpg_strerror (rc));
2007       http_release_parsed_uri (uri);
2008       return 1;
2009     }
2010
2011   printf ("Scheme: %s\n", uri->scheme);
2012   printf ("Host  : %s\n", uri->host);
2013   printf ("Port  : %u\n", uri->port);
2014   printf ("Path  : %s\n", uri->path);
2015   for (r = uri->params; r; r = r->next)
2016     {
2017       printf ("Params: %s", r->name);
2018       if (!r->no_value)
2019         {
2020           printf ("=%s", r->value);
2021           if (strlen (r->value) != r->valuelen)
2022             printf (" [real length=%d]", (int) r->valuelen);
2023         }
2024       putchar ('\n');
2025     }
2026   for (r = uri->query; r; r = r->next)
2027     {
2028       printf ("Query : %s", r->name);
2029       if (!r->no_value)
2030         {
2031           printf ("=%s", r->value);
2032           if (strlen (r->value) != r->valuelen)
2033             printf (" [real length=%d]", (int) r->valuelen);
2034         }
2035       putchar ('\n');
2036     }
2037   http_release_parsed_uri (uri);
2038   uri = NULL;
2039
2040   rc = http_open_document (&hd, *argv, NULL, 
2041                            HTTP_FLAG_NO_SHUTDOWN | HTTP_FLAG_NEED_HEADER,
2042                            NULL, tls_session);
2043   if (rc)
2044     {
2045       log_error ("can't get `%s': %s\n", *argv, gpg_strerror (rc));
2046       return 1;
2047     }
2048   log_info ("open_http_document succeeded; status=%u\n",
2049             http_get_status_code (hd));
2050   for (hdr = hd->headers; hdr; hdr = hdr->next)
2051     printf ("HDR: %s: %s\n", hdr->name, hdr->value);
2052   switch (http_get_status_code (hd))
2053     {
2054     case 200:
2055       while ((c = P_ES(getc) (http_get_read_ptr (hd))) != EOF)
2056         putchar (c);
2057       break;
2058     case 301:
2059     case 302:
2060       printf ("Redirected to `%s'\n", http_get_header (hd, "Location"));
2061       break;
2062     }
2063   http_close (hd, 0);
2064
2065 #ifdef HTTP_USE_GNUTLS
2066   gnutls_deinit (tls_session);
2067   gnutls_certificate_free_credentials (certcred);
2068   gnutls_global_deinit ();
2069 #endif /*HTTP_USE_GNUTLS*/
2070
2071   return 0;
2072 }
2073 #endif /*TEST*/
2074
2075
2076 /*
2077 Local Variables:
2078 compile-command: "gcc -I.. -I../gl -DTEST -DHAVE_CONFIG_H -Wall -O2 -g -o http-test http.c -L. -lcommon -L../jnlib -ljnlib -lgcrypt -lpth -lgnutls"
2079 End:
2080 */