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