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