2008-02-01 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / common / http.c
blob5f7c053fdd469cd0ee5436cbd6ef6246a34f7bb1
1 /* http.c - HTTP protocol handler
2 * Copyright (C) 1999, 2001, 2002, 2003, 2004,
3 * 2006 Free Software Foundation, Inc.
5 * This file is part of GnuPG.
7 * GnuPG is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
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.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 /* Simple HTTP client implementation. We try to keep the code as
22 self-contained as possible. There are some contraints however:
24 - stpcpy is required
25 - fixme: list other requirements.
28 - With HTTP_USE_ESTREAM defined, all I/O is done through estream.
29 - With HTTP_USE_GNUTLS support for https is provided (this also
30 requires estream).
31 - With HTTP_NO_WSASTARTUP the socket initialization is not done
32 under Windows. This is useful if the socket layer has already
33 been initialized elsewhere. This also avoids the installation of
34 an exit handler to cleanup the socket layer.
37 #ifdef HAVE_CONFIG_H
38 # include <config.h>
39 #endif
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <stdarg.h>
43 #include <string.h>
44 #include <ctype.h>
45 #include <errno.h>
46 #include <unistd.h>
48 #ifdef HAVE_W32_SYSTEM
49 # include <windows.h>
50 #else /*!HAVE_W32_SYSTEM*/
51 # include <sys/types.h>
52 # include <sys/socket.h>
53 # include <sys/time.h>
54 # include <time.h>
55 # include <netinet/in.h>
56 # include <arpa/inet.h>
57 # include <netdb.h>
58 #endif /*!HAVE_W32_SYSTEM*/
60 #ifdef HTTP_USE_GNUTLS
61 # include <gnutls/gnutls.h>
62 /* For non-understandable reasons GNUTLS dropped the _t suffix from
63 all types. yes, ISO-C might be read as this but there are still
64 other name space conflicts and using _t is actually a Good
65 Thing. */
66 typedef gnutls_session gnutls_session_t;
67 typedef gnutls_transport_ptr gnutls_transport_ptr_t;
68 #endif /*HTTP_USE_GNUTLS*/
70 #ifdef TEST
71 #undef USE_DNS_SRV
72 #endif
74 #include "util.h"
75 #include "i18n.h"
76 #include "http.h"
77 #ifdef USE_DNS_SRV
78 #include "srv.h"
79 #else /*!USE_DNS_SRV*/
80 /* If we are not compiling with SRV record support we provide stub
81 data structures. */
82 #ifndef MAXDNAME
83 #define MAXDNAME 1025
84 #endif
85 struct srventry
87 unsigned short priority;
88 unsigned short weight;
89 unsigned short port;
90 int run_count;
91 char target[MAXDNAME];
93 #endif/*!USE_DNS_SRV*/
96 #ifdef HAVE_W32_SYSTEM
97 #define sock_close(a) closesocket(a)
98 #else
99 #define sock_close(a) close(a)
100 #endif
102 #ifndef EAGAIN
103 #define EAGAIN EWOULDBLOCK
104 #endif
106 #define HTTP_PROXY_ENV "http_proxy"
107 #define MAX_LINELEN 20000 /* Max. length of a HTTP header line. */
108 #define VALID_URI_CHARS "abcdefghijklmnopqrstuvwxyz" \
109 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
110 "01234567890@" \
111 "!\"#$%&'()*+,-./:;<=>?[\\]^_{|}~"
113 /* Define a prefix to map stream functions to the estream library. */
114 #ifdef HTTP_USE_ESTREAM
115 #define P_ES(a) es_ ## a
116 #else
117 #define P_ES(a) a
118 #endif
119 #ifndef HTTP_USE_GNUTLS
120 typedef void * gnutls_session_t;
121 #endif
122 #if defined(HTTP_USE_GNUTLS) && !defined(HTTP_USE_ESTREAM)
123 #error Use of GNUTLS also requires support for Estream
124 #endif
126 static gpg_error_t do_parse_uri (parsed_uri_t uri, int only_local_part);
127 static int remove_escapes (char *string);
128 static int insert_escapes (char *buffer, const char *string,
129 const char *special);
130 static uri_tuple_t parse_tuple (char *string);
131 static gpg_error_t send_request (http_t hd,
132 const char *auth, const char *proxy);
133 static char *build_rel_path (parsed_uri_t uri);
134 static gpg_error_t parse_response (http_t hd);
136 static int connect_server (const char *server, unsigned short port,
137 unsigned int flags, const char *srvtag);
138 static gpg_error_t write_server (int sock, const char *data, size_t length);
140 #ifdef HTTP_USE_ESTREAM
141 static ssize_t cookie_read (void *cookie, void *buffer, size_t size);
142 static ssize_t cookie_write (void *cookie, const void *buffer, size_t size);
143 static int cookie_close (void *cookie);
145 static es_cookie_io_functions_t cookie_functions =
147 cookie_read,
148 cookie_write,
149 NULL,
150 cookie_close
153 struct cookie_s
155 int fd; /* File descriptor or -1 if already closed. */
156 gnutls_session_t tls_session; /* TLS session context or NULL if not used. */
157 int keep_socket; /* Flag to communicate with teh close handler. */
159 typedef struct cookie_s *cookie_t;
161 #endif /*HTTP_USE_ESTREAM*/
163 #ifdef HTTP_USE_GNUTLS
164 static gpg_error_t (*tls_callback) (http_t, gnutls_session_t, int);
165 #endif /*HTTP_USE_GNUTLS*/
168 /* An object to save header lines. */
169 struct header_s
171 struct header_s *next;
172 char *value; /* The value of the header (malloced). */
173 char name[1]; /* The name of the header (canonicalized). */
175 typedef struct header_s *header_t;
178 /* Our handle context. */
179 struct http_context_s
181 unsigned int status_code;
182 int sock;
183 int in_data;
184 #ifdef HTTP_USE_ESTREAM
185 estream_t fp_read;
186 estream_t fp_write;
187 void *write_cookie;
188 #else /*!HTTP_USE_ESTREAM*/
189 FILE *fp_read;
190 FILE *fp_write;
191 #endif /*!HTTP_USE_ESTREAM*/
192 void *tls_context;
193 int is_http_0_9;
194 parsed_uri_t uri;
195 http_req_t req_type;
196 char *buffer; /* Line buffer. */
197 size_t buffer_size;
198 unsigned int flags;
199 header_t headers; /* Received headers. */
205 #if defined(HAVE_W32_SYSTEM) && !defined(HTTP_NO_WSASTARTUP)
207 #if GNUPG_MAJOR_VERSION == 1
208 #define REQ_WINSOCK_MAJOR 1
209 #define REQ_WINSOCK_MINOR 1
210 #else
211 #define REQ_WINSOCK_MAJOR 2
212 #define REQ_WINSOCK_MINOR 2
213 #endif
216 static void
217 deinit_sockets (void)
219 WSACleanup();
222 static void
223 init_sockets (void)
225 static int initialized;
226 static WSADATA wsdata;
228 if (initialized)
229 return;
231 if ( WSAStartup( MAKEWORD (REQ_WINSOCK_MINOR, REQ_WINSOCK_MAJOR), &wsdata ) )
233 log_error ("error initializing socket library: ec=%d\n",
234 (int)WSAGetLastError () );
235 return;
237 if ( LOBYTE(wsdata.wVersion) != REQ_WINSOCK_MAJOR
238 || HIBYTE(wsdata.wVersion) != REQ_WINSOCK_MINOR )
240 log_error ("socket library version is %x.%x - but %d.%d needed\n",
241 LOBYTE(wsdata.wVersion), HIBYTE(wsdata.wVersion),
242 REQ_WINSOCK_MAJOR, REQ_WINSOCK_MINOR);
243 WSACleanup();
244 return;
246 atexit ( deinit_sockets );
247 initialized = 1;
249 #endif /*HAVE_W32_SYSTEM && !HTTP_NO_WSASTARTUP*/
254 * Helper function to create an HTTP header with hex encoded data. A
255 * new buffer is returned. This buffer is the concatenation of the
256 * string PREFIX, the hex-encoded DATA of length LEN and the string
257 * SUFFIX. On error NULL is returned and ERRNO set.
259 static char *
260 make_header_line (const char *prefix, const char *suffix,
261 const void *data, size_t len )
263 static unsigned char bintoasc[] =
264 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
265 "abcdefghijklmnopqrstuvwxyz"
266 "0123456789+/";
267 const unsigned int *s = data;
268 char *buffer, *p;
270 buffer = xtrymalloc (strlen (prefix) + (len+2)/3*4 + strlen (suffix) + 1);
271 if (!buffer)
272 return NULL;
273 p = stpcpy (buffer, prefix);
274 for ( ; len >= 3 ; len -= 3, s += 3 )
276 *p++ = bintoasc[(s[0] >> 2) & 077];
277 *p++ = bintoasc[(((s[0] <<4)&060)|((s[1] >> 4)&017))&077];
278 *p++ = bintoasc[(((s[1]<<2)&074)|((s[2]>>6)&03))&077];
279 *p++ = bintoasc[s[2]&077];
281 if ( len == 2 )
283 *p++ = bintoasc[(s[0] >> 2) & 077];
284 *p++ = bintoasc[(((s[0] <<4)&060)|((s[1] >> 4)&017))&077];
285 *p++ = bintoasc[((s[1]<<2)&074)];
286 *p++ = '=';
288 else if ( len == 1 )
290 *p++ = bintoasc[(s[0] >> 2) & 077];
291 *p++ = bintoasc[(s[0] <<4)&060];
292 *p++ = '=';
293 *p++ = '=';
295 strcpy (p, suffix);
296 return buffer;
302 void
303 http_register_tls_callback ( gpg_error_t (*cb) (http_t, void *, int) )
305 #ifdef HTTP_USE_GNUTLS
306 tls_callback = (gpg_error_t (*) (http_t, gnutls_session_t, int))cb;
307 #endif
312 /* Start a HTTP retrieval and return on success in R_HD a context
313 pointer for completing the the request and to wait for the
314 response. */
315 gpg_error_t
316 http_open (http_t *r_hd, http_req_t reqtype, const char *url,
317 const char *auth, unsigned int flags, const char *proxy,
318 void *tls_context)
320 gpg_error_t err;
321 http_t hd;
323 *r_hd = NULL;
325 if (!(reqtype == HTTP_REQ_GET || reqtype == HTTP_REQ_POST))
326 return gpg_error (GPG_ERR_INV_ARG);
328 /* Create the handle. */
329 hd = xtrycalloc (1, sizeof *hd);
330 if (!hd)
331 return gpg_error_from_syserror ();
332 hd->sock = -1;
333 hd->req_type = reqtype;
334 hd->flags = flags;
335 hd->tls_context = tls_context;
337 err = http_parse_uri (&hd->uri, url);
338 if (!err)
339 err = send_request (hd, auth, proxy);
341 if (err)
343 if (!hd->fp_read && !hd->fp_write && hd->sock != -1)
344 sock_close (hd->sock);
345 if (hd->fp_read)
346 P_ES(fclose) (hd->fp_read);
347 if (hd->fp_write)
348 P_ES(fclose) (hd->fp_write);
349 http_release_parsed_uri (hd->uri);
350 xfree (hd);
352 else
353 *r_hd = hd;
354 return err;
358 void
359 http_start_data (http_t hd)
361 if (!hd->in_data)
363 #ifdef HTTP_USE_ESTREAM
364 es_fputs ("\r\n", hd->fp_write);
365 es_fflush (hd->fp_write);
366 #else
367 fflush (hd->fp_write);
368 write_server (hd->sock, "\r\n", 2);
369 #endif
370 hd->in_data = 1;
372 else
373 P_ES(fflush) (hd->fp_write);
377 gpg_error_t
378 http_wait_response (http_t hd)
380 gpg_error_t err;
382 /* Make sure that we are in the data. */
383 http_start_data (hd);
385 /* We dup the socket, to cope with the fact that fclose closes the
386 underlying socket. In TLS mode we don't do that because we can't
387 close the socket gnutls is working on; instead we make sure that
388 the fclose won't close the socket in this case. */
389 #ifdef HTTP_USE_ESTREAM
390 if (hd->write_cookie)
392 /* The write cookie is only set in the TLS case. */
393 cookie_t cookie = hd->write_cookie;
394 cookie->keep_socket = 1;
396 else
397 #endif /*HTTP_USE_ESTREAM*/
399 hd->sock = dup (hd->sock);
400 if (hd->sock == -1)
401 return gpg_error_from_syserror ();
403 P_ES(fclose) (hd->fp_write);
404 hd->fp_write = NULL;
405 #ifdef HTTP_USE_ESTREAM
406 hd->write_cookie = NULL;
407 #endif
409 if (!(hd->flags & HTTP_FLAG_NO_SHUTDOWN))
410 shutdown (hd->sock, 1);
411 hd->in_data = 0;
413 #ifdef HTTP_USE_ESTREAM
415 cookie_t cookie;
417 cookie = xtrycalloc (1, sizeof *cookie);
418 if (!cookie)
419 return gpg_error_from_syserror ();
420 cookie->fd = hd->sock;
421 if (hd->uri->use_tls)
422 cookie->tls_session = hd->tls_context;
424 hd->fp_read = es_fopencookie (cookie, "r", cookie_functions);
425 if (!hd->fp_read)
427 xfree (cookie);
428 return gpg_error_from_syserror ();
431 #else /*!HTTP_USE_ESTREAM*/
432 hd->fp_read = fdopen (hd->sock, "r");
433 if (!hd->fp_read)
434 return gpg_error_from_syserror ();
435 #endif /*!HTTP_USE_ESTREAM*/
437 err = parse_response (hd);
438 return err;
442 /* Convenience function to send a request and wait for the response.
443 Closes the handle on error. If PROXY is not NULL, this value will
444 be used as an HTTP proxy and any enabled $http_proxy gets
445 ignored. */
446 gpg_error_t
447 http_open_document (http_t *r_hd, const char *document,
448 const char *auth, unsigned int flags, const char *proxy,
449 void *tls_context)
451 gpg_error_t err;
453 err = http_open (r_hd, HTTP_REQ_GET, document, auth, flags,
454 proxy, tls_context);
455 if (err)
456 return err;
458 err = http_wait_response (*r_hd);
459 if (err)
460 http_close (*r_hd, 0);
462 return err;
466 void
467 http_close (http_t hd, int keep_read_stream)
469 if (!hd)
470 return;
471 if (!hd->fp_read && !hd->fp_write && hd->sock != -1)
472 sock_close (hd->sock);
473 if (hd->fp_read && !keep_read_stream)
474 P_ES(fclose) (hd->fp_read);
475 if (hd->fp_write)
476 P_ES(fclose) (hd->fp_write);
477 http_release_parsed_uri (hd->uri);
478 while (hd->headers)
480 header_t tmp = hd->headers->next;
481 xfree (hd->headers->value);
482 xfree (hd->headers);
483 hd->headers = tmp;
485 xfree (hd->buffer);
486 xfree (hd);
490 #ifdef HTTP_USE_ESTREAM
491 estream_t
492 http_get_read_ptr (http_t hd)
494 return hd?hd->fp_read:NULL;
496 estream_t
497 http_get_write_ptr (http_t hd)
499 return hd?hd->fp_write:NULL;
501 #else /*!HTTP_USE_ESTREAM*/
502 FILE *
503 http_get_read_ptr (http_t hd)
505 return hd?hd->fp_read:NULL;
507 FILE *
508 http_get_write_ptr (http_t hd)
510 return hd?hd->fp_write:NULL;
512 #endif /*!HTTP_USE_ESTREAM*/
513 unsigned int
514 http_get_status_code (http_t hd)
516 return hd?hd->status_code:0;
522 * Parse an URI and put the result into the newly allocated RET_URI.
523 * The caller must always use release_parsed_uri() to releases the
524 * resources (even on error).
526 gpg_error_t
527 http_parse_uri (parsed_uri_t * ret_uri, const char *uri)
529 *ret_uri = xcalloc (1, sizeof **ret_uri + strlen (uri));
530 strcpy ((*ret_uri)->buffer, uri);
531 return do_parse_uri (*ret_uri, 0);
534 void
535 http_release_parsed_uri (parsed_uri_t uri)
537 if (uri)
539 uri_tuple_t r, r2;
541 for (r = uri->query; r; r = r2)
543 r2 = r->next;
544 xfree (r);
546 xfree (uri);
551 static gpg_error_t
552 do_parse_uri (parsed_uri_t uri, int only_local_part)
554 uri_tuple_t *tail;
555 char *p, *p2, *p3, *pp;
556 int n;
558 p = uri->buffer;
559 n = strlen (uri->buffer);
561 /* Initialize all fields to an empty string or an empty list. */
562 uri->scheme = uri->host = uri->path = p + n;
563 uri->port = 0;
564 uri->params = uri->query = NULL;
565 uri->use_tls = 0;
567 /* A quick validity check. */
568 if (strspn (p, VALID_URI_CHARS) != n)
569 return gpg_error (GPG_ERR_BAD_URI); /* Invalid characters found. */
571 if (!only_local_part)
573 /* Find the scheme. */
574 if (!(p2 = strchr (p, ':')) || p2 == p)
575 return gpg_error (GPG_ERR_BAD_URI); /* No scheme. */
576 *p2++ = 0;
577 for (pp=p; *pp; pp++)
578 *pp = tolower (*(unsigned char*)pp);
579 uri->scheme = p;
580 if (!strcmp (uri->scheme, "http"))
581 uri->port = 80;
582 #ifdef HTTP_USE_GNUTLS
583 else if (!strcmp (uri->scheme, "https"))
585 uri->port = 443;
586 uri->use_tls = 1;
588 #endif
589 else
590 return gpg_error (GPG_ERR_INV_URI); /* Unsupported scheme */
592 p = p2;
594 /* Find the hostname */
595 if (*p != '/')
596 return gpg_error (GPG_ERR_INV_URI); /* Does not start with a slash. */
598 p++;
599 if (*p == '/') /* There seems to be a hostname. */
601 p++;
602 if ((p2 = strchr (p, '/')))
603 *p2++ = 0;
605 /* Check for username/password encoding */
606 if ((p3 = strchr (p, '@')))
608 uri->auth = p;
609 *p3++ = '\0';
610 p = p3;
613 for (pp=p; *pp; pp++)
614 *pp = tolower (*(unsigned char*)pp);
615 uri->host = p;
616 if ((p3 = strchr (p, ':')))
618 *p3++ = 0;
619 uri->port = atoi (p3);
622 uri->host = p;
623 if ((n = remove_escapes (uri->host)) < 0)
624 return gpg_error (GPG_ERR_BAD_URI);
625 if (n != strlen (p))
626 return gpg_error (GPG_ERR_BAD_URI); /* Hostname incudes a Nul. */
627 p = p2 ? p2 : NULL;
629 } /* End global URI part. */
631 /* Parse the pathname part */
632 if (!p || !*p)
633 return 0; /* We don't have a path. Okay. */
635 /* TODO: Here we have to check params. */
637 /* Do we have a query part? */
638 if ((p2 = strchr (p, '?')))
639 *p2++ = 0;
641 uri->path = p;
642 if ((n = remove_escapes (p)) < 0)
643 return gpg_error (GPG_ERR_BAD_URI);
644 if (n != strlen (p))
645 return gpg_error (GPG_ERR_BAD_URI); /* Path includes a Nul. */
646 p = p2 ? p2 : NULL;
648 if (!p || !*p)
649 return 0; /* We don't have a query string. Okay. */
651 /* Now parse the query string. */
652 tail = &uri->query;
653 for (;;)
655 uri_tuple_t elem;
657 if ((p2 = strchr (p, '&')))
658 *p2++ = 0;
659 if (!(elem = parse_tuple (p)))
660 return gpg_error (GPG_ERR_BAD_URI);
661 *tail = elem;
662 tail = &elem->next;
664 if (!p2)
665 break; /* Ready. */
666 p = p2;
669 return 0;
674 * Remove all %xx escapes; this is done in-place. Returns: New length
675 * of the string.
677 static int
678 remove_escapes (char *string)
680 int n = 0;
681 unsigned char *p, *s;
683 for (p = s = (unsigned char*)string; *s; s++)
685 if (*s == '%')
687 if (s[1] && s[2] && isxdigit (s[1]) && isxdigit (s[2]))
689 s++;
690 *p = *s >= '0' && *s <= '9' ? *s - '0' :
691 *s >= 'A' && *s <= 'F' ? *s - 'A' + 10 : *s - 'a' + 10;
692 *p <<= 4;
693 s++;
694 *p |= *s >= '0' && *s <= '9' ? *s - '0' :
695 *s >= 'A' && *s <= 'F' ? *s - 'A' + 10 : *s - 'a' + 10;
696 p++;
697 n++;
699 else
701 *p++ = *s++;
702 if (*s)
703 *p++ = *s++;
704 if (*s)
705 *p++ = *s++;
706 if (*s)
707 *p = 0;
708 return -1; /* Bad URI. */
711 else
713 *p++ = *s;
714 n++;
717 *p = 0; /* Make sure to keep a string terminator. */
718 return n;
722 static int
723 insert_escapes (char *buffer, const char *string,
724 const char *special)
726 const unsigned char *s = (const unsigned char*)string;
727 int n = 0;
729 for (; *s; s++)
731 if (strchr (VALID_URI_CHARS, *s) && !strchr (special, *s))
733 if (buffer)
734 *(unsigned char*)buffer++ = *s;
735 n++;
737 else
739 if (buffer)
741 sprintf (buffer, "%%%02X", *s);
742 buffer += 3;
744 n += 3;
747 return n;
751 /* Allocate a new string from STRING using standard HTTP escaping as
752 well as escaping of characters given in SPECIALS. A common pattern
753 for SPECIALS is "%;?&=". However it depends on the needs, for
754 example "+" and "/: often needs to be escaped too. Returns NULL on
755 failure and sets ERRNO. */
756 char *
757 http_escape_string (const char *string, const char *specials)
759 int n;
760 char *buf;
762 n = insert_escapes (NULL, string, specials);
763 buf = xtrymalloc (n+1);
764 if (buf)
766 insert_escapes (buf, string, specials);
767 buf[n] = 0;
769 return buf;
774 static uri_tuple_t
775 parse_tuple (char *string)
777 char *p = string;
778 char *p2;
779 int n;
780 uri_tuple_t tuple;
782 if ((p2 = strchr (p, '=')))
783 *p2++ = 0;
784 if ((n = remove_escapes (p)) < 0)
785 return NULL; /* Bad URI. */
786 if (n != strlen (p))
787 return NULL; /* Name with a Nul in it. */
788 tuple = xtrycalloc (1, sizeof *tuple);
789 if (!tuple)
790 return NULL; /* Out of core. */
791 tuple->name = p;
792 if (!p2) /* We have only the name, so we assume an empty value string. */
794 tuple->value = p + strlen (p);
795 tuple->valuelen = 0;
796 tuple->no_value = 1; /* Explicitly mark that we have seen no '='. */
798 else /* Name and value. */
800 if ((n = remove_escapes (p2)) < 0)
802 xfree (tuple);
803 return NULL; /* Bad URI. */
805 tuple->value = p2;
806 tuple->valuelen = n;
808 return tuple;
813 * Send a HTTP request to the server
814 * Returns 0 if the request was successful
816 static gpg_error_t
817 send_request (http_t hd, const char *auth, const char *proxy)
819 gnutls_session_t tls_session;
820 gpg_error_t err;
821 const char *server;
822 char *request, *p;
823 unsigned short port;
824 const char *http_proxy = NULL;
825 char *proxy_authstr = NULL;
826 char *authstr = NULL;
827 int save_errno;
829 tls_session = hd->tls_context;
830 if (hd->uri->use_tls && !tls_session)
832 log_error ("TLS requested but no GNUTLS context provided\n");
833 return gpg_error (GPG_ERR_INTERNAL);
836 server = *hd->uri->host ? hd->uri->host : "localhost";
837 port = hd->uri->port ? hd->uri->port : 80;
839 if ( (proxy && *proxy)
840 || ( (hd->flags & HTTP_FLAG_TRY_PROXY)
841 && (http_proxy = getenv (HTTP_PROXY_ENV))
842 && *http_proxy ))
844 parsed_uri_t uri;
846 if (proxy)
847 http_proxy = proxy;
849 err = http_parse_uri (&uri, http_proxy);
850 if (err)
852 log_error ("invalid HTTP proxy (%s): %s\n",
853 http_proxy, gpg_strerror (err));
854 http_release_parsed_uri (uri);
855 return gpg_error (GPG_ERR_CONFIGURATION);
859 if (uri->auth)
861 remove_escapes (uri->auth);
862 proxy_authstr = make_header_line ("Proxy-Authorization: Basic ",
863 "\r\n",
864 uri->auth, strlen(uri->auth));
865 if (!proxy_authstr)
867 err = gpg_error_from_syserror ();
868 http_release_parsed_uri (uri);
869 return err;
873 hd->sock = connect_server (*uri->host ? uri->host : "localhost",
874 uri->port ? uri->port : 80,
875 hd->flags, hd->uri->scheme);
876 save_errno = errno;
877 http_release_parsed_uri (uri);
879 else
881 hd->sock = connect_server (server, port, hd->flags, hd->uri->scheme);
882 save_errno = errno;
885 if (hd->sock == -1)
887 xfree (proxy_authstr);
888 return (save_errno
889 ? gpg_error_from_errno (save_errno)
890 : gpg_error (GPG_ERR_NOT_FOUND));
893 #ifdef HTTP_USE_GNUTLS
894 if (hd->uri->use_tls)
896 int rc;
898 gnutls_transport_set_ptr (tls_session, (gnutls_transport_ptr_t)hd->sock);
901 rc = gnutls_handshake (tls_session);
903 while (rc == GNUTLS_E_INTERRUPTED || rc == GNUTLS_E_AGAIN);
904 if (rc < 0)
906 log_info ("TLS handshake failed: %s\n", gnutls_strerror (rc));
907 xfree (proxy_authstr);
908 return gpg_error (GPG_ERR_NETWORK);
911 if (tls_callback)
913 err = tls_callback (hd, tls_session, 0);
914 if (err)
916 log_info ("TLS connection authentication failed: %s\n",
917 gpg_strerror (err));
918 xfree (proxy_authstr);
919 return err;
923 #endif /*HTTP_USE_GNUTLS*/
925 if (auth || hd->uri->auth)
927 char *myauth;
929 if (auth)
931 myauth = xtrystrdup (auth);
932 if (!myauth)
934 xfree (proxy_authstr);
935 return gpg_error_from_syserror ();
937 remove_escapes (myauth);
939 else
941 remove_escapes (hd->uri->auth);
942 myauth = hd->uri->auth;
945 authstr = make_header_line ("Authorization: Basic %s", "\r\n",
946 myauth, strlen (myauth));
947 if (auth)
948 xfree (myauth);
950 if (!authstr)
952 xfree (proxy_authstr);
953 return gpg_error_from_syserror ();
957 p = build_rel_path (hd->uri);
958 if (!p)
959 return gpg_error_from_syserror ();
961 request = xtrymalloc (2 * strlen (server)
962 + strlen (p)
963 + (authstr?strlen(authstr):0)
964 + (proxy_authstr?strlen(proxy_authstr):0)
965 + 100);
966 if (!request)
968 err = gpg_error_from_syserror ();
969 xfree (p);
970 xfree (authstr);
971 xfree (proxy_authstr);
972 return err;
975 if (http_proxy && *http_proxy)
977 sprintf (request, "%s http://%s:%hu%s%s HTTP/1.0\r\n%s%s",
978 hd->req_type == HTTP_REQ_GET ? "GET" :
979 hd->req_type == HTTP_REQ_HEAD ? "HEAD" :
980 hd->req_type == HTTP_REQ_POST ? "POST" : "OOPS",
981 server, port, *p == '/' ? "" : "/", p,
982 authstr ? authstr : "",
983 proxy_authstr ? proxy_authstr : "");
985 else
987 char portstr[35];
989 if (port == 80)
990 *portstr = 0;
991 else
992 sprintf (portstr, ":%u", port);
994 sprintf (request, "%s %s%s HTTP/1.0\r\nHost: %s%s\r\n%s",
995 hd->req_type == HTTP_REQ_GET ? "GET" :
996 hd->req_type == HTTP_REQ_HEAD ? "HEAD" :
997 hd->req_type == HTTP_REQ_POST ? "POST" : "OOPS",
998 *p == '/' ? "" : "/", p, server, portstr,
999 authstr? authstr:"");
1001 xfree (p);
1004 #ifdef HTTP_USE_ESTREAM
1005 /* First setup estream so that we can write even the first line
1006 using estream. This is also required for the sake of gnutls. */
1008 cookie_t cookie;
1010 cookie = xtrycalloc (1, sizeof *cookie);
1011 if (!cookie)
1013 err = gpg_error_from_syserror ();
1014 goto leave;
1016 cookie->fd = hd->sock;
1017 if (hd->uri->use_tls)
1019 cookie->tls_session = tls_session;
1020 hd->write_cookie = cookie;
1023 hd->fp_write = es_fopencookie (cookie, "w", cookie_functions);
1024 if (!hd->fp_write)
1026 xfree (cookie);
1027 err = gpg_error_from_syserror ();
1029 else if (es_fputs (request, hd->fp_write) || es_fflush (hd->fp_write))
1030 err = gpg_error_from_syserror ();
1031 else
1032 err = 0;
1035 leave:
1037 #else /*!HTTP_USE_ESTREAM*/
1038 /* We send out the start of the request through our own send
1039 function and only then assign a stdio stream. This allows for
1040 better error reporting that through standard stdio means. */
1041 err = write_server (hd->sock, request, strlen (request));
1042 if (!err)
1044 hd->fp_write = fdopen (hd->sock, "w");
1045 if (!hd->fp_write)
1046 err = gpg_error_from_syserror ();
1048 #endif /*!HTTP_USE_ESTREAM*/
1050 xfree (request);
1051 xfree (authstr);
1052 xfree (proxy_authstr);
1054 return err;
1059 * Build the relative path from the parsed URI. Minimal
1060 * implementation. May return NULL in case of memory failure; errno
1061 * is then set accordingly.
1063 static char *
1064 build_rel_path (parsed_uri_t uri)
1066 uri_tuple_t r;
1067 char *rel_path, *p;
1068 int n;
1070 /* Count the needed space. */
1071 n = insert_escapes (NULL, uri->path, "%;?&");
1072 /* TODO: build params. */
1073 for (r = uri->query; r; r = r->next)
1075 n++; /* '?'/'&' */
1076 n += insert_escapes (NULL, r->name, "%;?&=");
1077 if (!r->no_value)
1079 n++; /* '=' */
1080 n += insert_escapes (NULL, r->value, "%;?&=");
1083 n++;
1085 /* Now allocate and copy. */
1086 p = rel_path = xtrymalloc (n);
1087 if (!p)
1088 return NULL;
1089 n = insert_escapes (p, uri->path, "%;?&");
1090 p += n;
1091 /* TODO: add params. */
1092 for (r = uri->query; r; r = r->next)
1094 *p++ = r == uri->query ? '?' : '&';
1095 n = insert_escapes (p, r->name, "%;?&=");
1096 p += n;
1097 if (!r->no_value)
1099 *p++ = '=';
1100 /* TODO: Use valuelen. */
1101 n = insert_escapes (p, r->value, "%;?&=");
1102 p += n;
1105 *p = 0;
1106 return rel_path;
1112 Same as fgets() but if the buffer is too short a larger one will be
1113 allocated up to some limit *MAX_LENGTH. A line is considered a
1114 byte stream ending in a LF. Returns the length of the line. EOF is
1115 indicated by a line of length zero. The last LF may be missing due
1116 to an EOF. If MAX_LENGTH is zero on return, the line has been
1117 truncated. If the returned buffer is NULL, not enough memory was
1118 enable to increase it, the return value will also be 0 and some
1119 bytes might have been lost which should be no problem becuase
1120 out-of-memory is pretty fatal for most applications.
1122 If a line has been truncated, the file pointer is internally moved
1123 forward to the end of the line.
1125 Note: The returned buffer is allocated with enough extra space to
1126 append a CR,LF,Nul
1128 static size_t
1129 my_read_line (
1130 #ifdef HTTP_USE_ESTREAM
1131 estream_t fp,
1132 #else
1133 FILE *fp,
1134 #endif
1135 char **addr_of_buffer,
1136 size_t *length_of_buffer, size_t *max_length)
1138 int c;
1139 char *buffer = *addr_of_buffer;
1140 size_t length = *length_of_buffer;
1141 size_t nbytes = 0;
1142 size_t maxlen = *max_length;
1143 char *p;
1145 if (!buffer) /* Must allocate a new buffer. */
1147 length = 256;
1148 buffer = xtrymalloc (length);
1149 *addr_of_buffer = buffer;
1150 if (!buffer)
1152 *length_of_buffer = *max_length = 0;
1153 return 0;
1155 *length_of_buffer = length;
1158 length -= 3; /* Reserve 3 bytes (cr,lf,eol). */
1159 p = buffer;
1160 while ((c = P_ES(getc) (fp)) != EOF)
1162 if (nbytes == length) /* Increase the buffer. */
1164 if (length > maxlen) /* Limit reached. */
1166 /* Skip the rest of the line. */
1167 while (c != '\n' && (c = P_ES(getc) (fp)) != EOF)
1169 *p++ = '\n'; /* Always append a LF (we reserved some space). */
1170 nbytes++;
1171 *max_length = 0; /* Indicate truncation */
1172 break; /*(the while loop)*/
1174 length += 3; /* Adjust for the reserved bytes. */
1175 length += length < 1024 ? 256 : 1024;
1176 *addr_of_buffer = xtryrealloc (buffer, length);
1177 if (!*addr_of_buffer)
1179 int save_errno = errno;
1180 xfree (buffer);
1181 *length_of_buffer = *max_length = 0;
1182 errno = save_errno;
1183 return 0;
1185 buffer = *addr_of_buffer;
1186 *length_of_buffer = length;
1187 length -= 3; /* And re-adjust for the reservation. */
1188 p = buffer + nbytes;
1190 *p++ = c;
1191 nbytes++;
1192 if (c == '\n')
1193 break;
1195 *p = 0; /* Make sure the line is a string. */
1197 return nbytes;
1201 /* Transform a header name into a standard capitalized format; e.g.
1202 "Content-Type". Conversion stops at the colon. As usual we don't
1203 use the localized versions of ctype.h. */
1204 static void
1205 capitalize_header_name (char *name)
1207 int first = 1;
1209 for (; *name && *name != ':'; name++)
1211 if (*name == '-')
1212 first = 1;
1213 else if (first)
1215 if (*name >= 'a' && *name <= 'z')
1216 *name = *name - 'a' + 'A';
1217 first = 0;
1219 else if (*name >= 'A' && *name <= 'Z')
1220 *name = *name - 'A' + 'a';
1225 /* Store an HTTP header line in LINE away. Line continuation is
1226 supported as well as merging of headers with the same name. This
1227 function may modify LINE. */
1228 static gpg_error_t
1229 store_header (http_t hd, char *line)
1231 size_t n;
1232 char *p, *value;
1233 header_t h;
1235 n = strlen (line);
1236 if (n && line[n-1] == '\n')
1238 line[--n] = 0;
1239 if (n && line[n-1] == '\r')
1240 line[--n] = 0;
1242 if (!n) /* we are never called to hit this. */
1243 return gpg_error (GPG_ERR_BUG);
1244 if (*line == ' ' || *line == '\t')
1246 /* Continuation. This won't happen too often as it is not
1247 recommended. We use a straightforward implementaion. */
1248 if (!hd->headers)
1249 return gpg_error (GPG_ERR_PROTOCOL_VIOLATION);
1250 n += strlen (hd->headers->value);
1251 p = xtrymalloc (n+1);
1252 if (!p)
1253 return gpg_error_from_syserror ();
1254 strcpy (stpcpy (p, hd->headers->value), line);
1255 xfree (hd->headers->value);
1256 hd->headers->value = p;
1257 return 0;
1260 capitalize_header_name (line);
1261 p = strchr (line, ':');
1262 if (!p)
1263 return gpg_error (GPG_ERR_PROTOCOL_VIOLATION);
1264 *p++ = 0;
1265 while (*p == ' ' || *p == '\t')
1266 p++;
1267 value = p;
1269 for (h=hd->headers; h; h = h->next)
1270 if ( !strcmp (h->name, line) )
1271 break;
1272 if (h)
1274 /* We have already seen a line with that name. Thus we assume
1275 it is a comma separated list and merge them. */
1276 p = xtrymalloc (strlen (h->value) + 1 + strlen (value)+ 1);
1277 if (!p)
1278 return gpg_error_from_syserror ();
1279 strcpy (stpcpy (stpcpy (p, h->value), ","), value);
1280 xfree (h->value);
1281 h->value = p;
1282 return 0;
1285 /* Append a new header. */
1286 h = xtrymalloc (sizeof *h + strlen (line));
1287 if (!h)
1288 return gpg_error_from_syserror ();
1289 strcpy (h->name, line);
1290 h->value = xtrymalloc (strlen (value)+1);
1291 if (!h->value)
1293 xfree (h);
1294 return gpg_error_from_syserror ();
1296 strcpy (h->value, value);
1297 h->next = hd->headers;
1298 hd->headers = h;
1300 return 0;
1304 /* Return the header NAME from the last response. The returned value
1305 is valid as along as HD has not been closed and no othe request has
1306 been send. If the header was not found, NULL is returned. Name
1307 must be canonicalized, that is the first letter of each dash
1308 delimited part must be uppercase and all other letters lowercase.
1309 Note that the context must have been opened with the
1310 HTTP_FLAG_NEED_HEADER. */
1311 const char *
1312 http_get_header (http_t hd, const char *name)
1314 header_t h;
1316 for (h=hd->headers; h; h = h->next)
1317 if ( !strcmp (h->name, name) )
1318 return h->value;
1319 return NULL;
1325 * Parse the response from a server.
1326 * Returns: Errorcode and sets some files in the handle
1328 static gpg_error_t
1329 parse_response (http_t hd)
1331 char *line, *p, *p2;
1332 size_t maxlen, len;
1334 /* Delete old header lines. */
1335 while (hd->headers)
1337 header_t tmp = hd->headers->next;
1338 xfree (hd->headers->value);
1339 xfree (hd->headers);
1340 hd->headers = tmp;
1343 /* Wait for the status line. */
1346 maxlen = MAX_LINELEN;
1347 len = my_read_line (hd->fp_read, &hd->buffer, &hd->buffer_size, &maxlen);
1348 line = hd->buffer;
1349 if (!line)
1350 return gpg_error_from_syserror (); /* Out of core. */
1351 if (!maxlen)
1352 return gpg_error (GPG_ERR_TRUNCATED); /* Line has been truncated. */
1353 if (!len)
1354 return gpg_error (GPG_ERR_EOF);
1355 if ( (hd->flags & HTTP_FLAG_LOG_RESP) )
1356 log_info ("RESP: `%.*s'\n",
1357 (int)strlen(line)-(*line&&line[1]?2:0),line);
1359 while (!*line);
1361 if ((p = strchr (line, '/')))
1362 *p++ = 0;
1363 if (!p || strcmp (line, "HTTP"))
1364 return 0; /* Assume http 0.9. */
1366 if ((p2 = strpbrk (p, " \t")))
1368 *p2++ = 0;
1369 p2 += strspn (p2, " \t");
1371 if (!p2)
1372 return 0; /* Also assume http 0.9. */
1373 p = p2;
1374 /* TODO: Add HTTP version number check. */
1375 if ((p2 = strpbrk (p, " \t")))
1376 *p2++ = 0;
1377 if (!isdigit ((unsigned int)p[0]) || !isdigit ((unsigned int)p[1])
1378 || !isdigit ((unsigned int)p[2]) || p[3])
1380 /* Malformed HTTP status code - assume http 0.9. */
1381 hd->is_http_0_9 = 1;
1382 hd->status_code = 200;
1383 return 0;
1385 hd->status_code = atoi (p);
1387 /* Skip all the header lines and wait for the empty line. */
1390 maxlen = MAX_LINELEN;
1391 len = my_read_line (hd->fp_read, &hd->buffer, &hd->buffer_size, &maxlen);
1392 line = hd->buffer;
1393 if (!line)
1394 return gpg_error_from_syserror (); /* Out of core. */
1395 /* Note, that we can silently ignore truncated lines. */
1396 if (!len)
1397 return gpg_error (GPG_ERR_EOF);
1398 /* Trim line endings of empty lines. */
1399 if ((*line == '\r' && line[1] == '\n') || *line == '\n')
1400 *line = 0;
1401 if ( (hd->flags & HTTP_FLAG_LOG_RESP) )
1402 log_info ("RESP: `%.*s'\n",
1403 (int)strlen(line)-(*line&&line[1]?2:0),line);
1404 if ( (hd->flags & HTTP_FLAG_NEED_HEADER) && *line )
1406 gpg_error_t err = store_header (hd, line);
1407 if (err)
1408 return err;
1411 while (len && *line);
1413 return 0;
1416 #if 0
1417 static int
1418 start_server ()
1420 struct sockaddr_in mya;
1421 struct sockaddr_in peer;
1422 int fd, client;
1423 fd_set rfds;
1424 int addrlen;
1425 int i;
1427 if ((fd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
1429 log_error ("socket() failed: %s\n", strerror (errno));
1430 return -1;
1432 i = 1;
1433 if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (byte *) & i, sizeof (i)))
1434 log_info ("setsockopt(SO_REUSEADDR) failed: %s\n", strerror (errno));
1436 mya.sin_family = AF_INET;
1437 memset (&mya.sin_addr, 0, sizeof (mya.sin_addr));
1438 mya.sin_port = htons (11371);
1440 if (bind (fd, (struct sockaddr *) &mya, sizeof (mya)))
1442 log_error ("bind to port 11371 failed: %s\n", strerror (errno));
1443 sock_close (fd);
1444 return -1;
1447 if (listen (fd, 5))
1449 log_error ("listen failed: %s\n", strerror (errno));
1450 sock_close (fd);
1451 return -1;
1454 for (;;)
1456 FD_ZERO (&rfds);
1457 FD_SET (fd, &rfds);
1459 if (select (fd + 1, &rfds, NULL, NULL, NULL) <= 0)
1460 continue; /* ignore any errors */
1462 if (!FD_ISSET (fd, &rfds))
1463 continue;
1465 addrlen = sizeof peer;
1466 client = accept (fd, (struct sockaddr *) &peer, &addrlen);
1467 if (client == -1)
1468 continue; /* oops */
1470 log_info ("connect from %s\n", inet_ntoa (peer.sin_addr));
1472 fflush (stdout);
1473 fflush (stderr);
1474 if (!fork ())
1476 int c;
1477 FILE *fp;
1479 fp = fdopen (client, "r");
1480 while ((c = getc (fp)) != EOF)
1481 putchar (c);
1482 fclose (fp);
1483 exit (0);
1485 sock_close (client);
1489 return 0;
1491 #endif
1493 /* Actually connect to a server. Returns the file descripto or -1 on
1494 error. ERRNO is set on error. */
1495 static int
1496 connect_server (const char *server, unsigned short port,
1497 unsigned int flags, const char *srvtag)
1499 int sock = -1;
1500 int srvcount = 0;
1501 int hostfound = 0;
1502 int srv, connected;
1503 int last_errno = 0;
1504 struct srventry *serverlist = NULL;
1506 #ifdef HAVE_W32_SYSTEM
1507 unsigned long inaddr;
1509 #ifndef HTTP_NO_WSASTARTUP
1510 init_sockets ();
1511 #endif
1512 /* Win32 gethostbyname doesn't handle IP addresses internally, so we
1513 try inet_addr first on that platform only. */
1514 inaddr = inet_addr(server);
1515 if ( inaddr != INADDR_NONE )
1517 struct sockaddr_in addr;
1519 memset(&addr,0,sizeof(addr));
1521 sock = socket(AF_INET,SOCK_STREAM,0);
1522 if ( sock==INVALID_SOCKET )
1524 log_error("error creating socket: ec=%d\n",(int)WSAGetLastError());
1525 return -1;
1528 addr.sin_family = AF_INET;
1529 addr.sin_port = htons(port);
1530 memcpy (&addr.sin_addr,&inaddr,sizeof(inaddr));
1532 if (!connect (sock,(struct sockaddr *)&addr,sizeof(addr)) )
1533 return sock;
1534 sock_close(sock);
1535 return -1;
1537 #endif /*HAVE_W32_SYSTEM*/
1539 #ifdef USE_DNS_SRV
1540 /* Do the SRV thing */
1541 if ((flags & HTTP_FLAG_TRY_SRV) && srvtag)
1543 /* We're using SRV, so append the tags. */
1544 if (1+strlen (srvtag) + 6 + strlen (server) + 1 <= MAXDNAME)
1546 char srvname[MAXDNAME];
1548 stpcpy (stpcpy (stpcpy (stpcpy (srvname,"_"), srvtag),
1549 "._tcp."), server);
1550 srvcount = getsrv (srvname, &serverlist);
1553 #endif /*USE_DNS_SRV*/
1555 if (!serverlist)
1557 /* Either we're not using SRV, or the SRV lookup failed. Make
1558 up a fake SRV record. */
1559 serverlist = xtrycalloc (1, sizeof *serverlist);
1560 if (!serverlist)
1561 return -1; /* Out of core. */
1562 serverlist->port = port;
1563 strncpy (serverlist->target, server, MAXDNAME);
1564 serverlist->target[MAXDNAME-1] = '\0';
1565 srvcount = 1;
1568 #ifdef HAVE_GETADDRINFO
1569 connected = 0;
1570 for (srv=0; srv < srvcount && !connected; srv++)
1572 struct addrinfo hints, *res, *ai;
1573 char portstr[35];
1575 sprintf (portstr, "%hu", port);
1576 memset (&hints, 0, sizeof (hints));
1577 hints.ai_socktype = SOCK_STREAM;
1578 if (getaddrinfo (serverlist[srv].target, portstr, &hints, &res))
1579 continue; /* Not found - try next one. */
1580 hostfound = 1;
1582 for (ai = res; ai && !connected; ai = ai->ai_next)
1584 if (sock != -1)
1585 sock_close (sock);
1586 sock = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol);
1587 if (sock == -1)
1589 int save_errno = errno;
1590 log_error ("error creating socket: %s\n", strerror (errno));
1591 freeaddrinfo (res);
1592 xfree (serverlist);
1593 errno = save_errno;
1594 return -1;
1597 if (connect (sock, ai->ai_addr, ai->ai_addrlen))
1598 last_errno = errno;
1599 else
1600 connected = 1;
1602 freeaddrinfo (res);
1604 #else /* !HAVE_GETADDRINFO */
1605 connected = 0;
1606 for (srv=0; srv < srvcount && !connected; srv++)
1608 int i;
1609 struct hostent *host = NULL;
1610 struct sockaddr_in addr;
1612 /* Note: This code is not thread-safe. */
1614 memset (&addr, 0, sizeof (addr));
1615 host = gethostbyname (serverlist[srv].target);
1616 if (!host)
1617 continue;
1618 hostfound = 1;
1620 if (sock != -1)
1621 sock_close (sock);
1622 sock = socket (host->h_addrtype, SOCK_STREAM, 0);
1623 if (sock == -1)
1625 log_error (_("error creating socket: %s\n"), strerror (errno));
1626 xfree (serverlist);
1627 return -1;
1630 addr.sin_family = host->h_addrtype;
1631 if (addr.sin_family != AF_INET)
1633 log_error ("unknown address family for `%s'\n",
1634 serverlist[srv].target);
1635 xfree (serverlist);
1636 return -1;
1638 addr.sin_port = htons (serverlist[srv].port);
1639 if (host->h_length != 4)
1641 log_error ("illegal address length for `%s'\n",
1642 serverlist[srv].target);
1643 xfree (serverlist);
1644 return -1;
1647 /* Try all A records until one responds. */
1648 for (i = 0; host->h_addr_list[i] && !connected; i++)
1650 memcpy (&addr.sin_addr, host->h_addr_list[i], host->h_length);
1651 if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)))
1652 last_errno = errno;
1653 else
1655 connected = 1;
1656 break;
1660 #endif /* !HAVE_GETADDRINFO */
1662 xfree (serverlist);
1664 if (!connected)
1666 #ifdef HAVE_W32_SYSTEM
1667 log_error ("can't connect to `%s': %s%sec=%d\n",
1668 server,
1669 hostfound? "":_("host not found"),
1670 hostfound? "":" - ", (int)WSAGetLastError());
1671 #else
1672 log_error ("can't connect to `%s': %s\n",
1673 server,
1674 hostfound? strerror (last_errno):"host not found");
1675 #endif
1676 if (sock != -1)
1677 sock_close (sock);
1678 errno = last_errno;
1679 return -1;
1681 return sock;
1685 static gpg_error_t
1686 write_server (int sock, const char *data, size_t length)
1688 int nleft;
1690 nleft = length;
1691 while (nleft > 0)
1693 #ifdef HAVE_W32_SYSTEM
1694 int nwritten;
1696 nwritten = send (sock, data, nleft, 0);
1697 if ( nwritten == SOCKET_ERROR )
1699 log_info ("network write failed: ec=%d\n", (int)WSAGetLastError ());
1700 return gpg_error (GPG_ERR_NETWORK);
1702 #else /*!HAVE_W32_SYSTEM*/
1703 int nwritten = write (sock, data, nleft);
1704 if (nwritten == -1)
1706 if (errno == EINTR)
1707 continue;
1708 if (errno == EAGAIN)
1710 struct timeval tv;
1712 tv.tv_sec = 0;
1713 tv.tv_usec = 50000;
1714 select (0, NULL, NULL, NULL, &tv);
1715 continue;
1717 log_info ("network write failed: %s\n", strerror (errno));
1718 return gpg_error_from_syserror ();
1720 #endif /*!HAVE_W32_SYSTEM*/
1721 nleft -= nwritten;
1722 data += nwritten;
1725 return 0;
1730 #ifdef HTTP_USE_ESTREAM
1731 /* Read handler for estream. */
1732 static ssize_t
1733 cookie_read (void *cookie, void *buffer, size_t size)
1735 cookie_t c = cookie;
1736 int nread;
1738 #ifdef HTTP_USE_GNUTLS
1739 if (c->tls_session)
1741 again:
1742 nread = gnutls_record_recv (c->tls_session, buffer, size);
1743 if (nread < 0)
1745 if (nread == GNUTLS_E_INTERRUPTED)
1746 goto again;
1747 if (nread == GNUTLS_E_AGAIN)
1749 struct timeval tv;
1751 tv.tv_sec = 0;
1752 tv.tv_usec = 50000;
1753 select (0, NULL, NULL, NULL, &tv);
1754 goto again;
1756 if (nread == GNUTLS_E_REHANDSHAKE)
1757 goto again; /* A client is allowed to just ignore this request. */
1758 log_info ("TLS network read failed: %s\n", gnutls_strerror (nread));
1759 errno = EIO;
1760 return -1;
1763 else
1764 #endif /*HTTP_USE_GNUTLS*/
1768 nread = read (c->fd, buffer, size);
1770 while (nread == -1 && errno == EINTR);
1773 return nread;
1776 /* Write handler for estream. */
1777 static ssize_t
1778 cookie_write (void *cookie, const void *buffer, size_t size)
1780 cookie_t c = cookie;
1781 int nwritten = 0;
1783 #ifdef HTTP_USE_GNUTLS
1784 if (c->tls_session)
1786 int nleft = size;
1787 while (nleft > 0)
1789 nwritten = gnutls_record_send (c->tls_session, buffer, nleft);
1790 if (nwritten <= 0)
1792 if (nwritten == GNUTLS_E_INTERRUPTED)
1793 continue;
1794 if (nwritten == GNUTLS_E_AGAIN)
1796 struct timeval tv;
1798 tv.tv_sec = 0;
1799 tv.tv_usec = 50000;
1800 select (0, NULL, NULL, NULL, &tv);
1801 continue;
1803 log_info ("TLS network write failed: %s\n",
1804 gnutls_strerror (nwritten));
1805 errno = EIO;
1806 return -1;
1808 nleft -= nwritten;
1809 buffer += nwritten;
1812 else
1813 #endif /*HTTP_USE_GNUTLS*/
1815 if ( write_server (c->fd, buffer, size) )
1817 errno = EIO;
1818 nwritten = -1;
1820 else
1821 nwritten = size;
1824 return nwritten;
1827 /* Close handler for estream. */
1828 static int
1829 cookie_close (void *cookie)
1831 cookie_t c = cookie;
1833 if (!c)
1834 return 0;
1836 #ifdef HTTP_USE_GNUTLS
1837 if (c->tls_session && !c->keep_socket)
1839 gnutls_bye (c->tls_session, GNUTLS_SHUT_RDWR);
1841 #endif /*HTTP_USE_GNUTLS*/
1842 if (c->fd != -1 && !c->keep_socket)
1843 sock_close (c->fd);
1845 xfree (c);
1846 return 0;
1848 #endif /*HTTP_USE_ESTREAM*/
1853 /**** Test code ****/
1854 #ifdef TEST
1856 static gpg_error_t
1857 verify_callback (http_t hd, void *tls_context, int reserved)
1859 log_info ("verification of certificates skipped\n");
1860 return 0;
1865 /* static void */
1866 /* my_gnutls_log (int level, const char *text) */
1867 /* { */
1868 /* fprintf (stderr, "gnutls:L%d: %s", level, text); */
1869 /* } */
1872 main (int argc, char **argv)
1874 int rc;
1875 parsed_uri_t uri;
1876 uri_tuple_t r;
1877 http_t hd;
1878 int c;
1879 gnutls_session_t tls_session = NULL;
1880 #ifdef HTTP_USE_GNUTLS
1881 gnutls_certificate_credentials certcred;
1882 const int certprio[] = { GNUTLS_CRT_X509, 0 };
1883 #endif /*HTTP_USE_GNUTLS*/
1884 header_t hdr;
1886 #ifdef HTTP_USE_ESTREAM
1887 es_init ();
1888 #endif
1889 log_set_prefix ("http-test", 1 | 4);
1890 if (argc == 1)
1892 /*start_server (); */
1893 return 0;
1896 if (argc != 2)
1898 fprintf (stderr, "usage: http-test uri\n");
1899 return 1;
1901 argc--;
1902 argv++;
1904 #ifdef HTTP_USE_GNUTLS
1905 rc = gnutls_global_init ();
1906 if (rc)
1907 log_error ("gnutls_global_init failed: %s\n", gnutls_strerror (rc));
1908 rc = gnutls_certificate_allocate_credentials (&certcred);
1909 if (rc)
1910 log_error ("gnutls_certificate_allocate_credentials failed: %s\n",
1911 gnutls_strerror (rc));
1912 /* rc = gnutls_certificate_set_x509_trust_file */
1913 /* (certcred, "ca.pem", GNUTLS_X509_FMT_PEM); */
1914 /* if (rc) */
1915 /* log_error ("gnutls_certificate_set_x509_trust_file failed: %s\n", */
1916 /* gnutls_strerror (rc)); */
1917 rc = gnutls_init (&tls_session, GNUTLS_CLIENT);
1918 if (rc)
1919 log_error ("gnutls_init failed: %s\n", gnutls_strerror (rc));
1920 rc = gnutls_set_default_priority (tls_session);
1921 if (rc)
1922 log_error ("gnutls_set_default_priority failed: %s\n",
1923 gnutls_strerror (rc));
1924 rc = gnutls_certificate_type_set_priority (tls_session, certprio);
1925 if (rc)
1926 log_error ("gnutls_certificate_type_set_priority failed: %s\n",
1927 gnutls_strerror (rc));
1928 rc = gnutls_credentials_set (tls_session, GNUTLS_CRD_CERTIFICATE, certcred);
1929 if (rc)
1930 log_error ("gnutls_credentials_set failed: %s\n", gnutls_strerror (rc));
1931 /* gnutls_global_set_log_function (my_gnutls_log); */
1932 /* gnutls_global_set_log_level (4); */
1934 http_register_tls_callback (verify_callback);
1935 #endif /*HTTP_USE_GNUTLS*/
1937 rc = http_parse_uri (&uri, *argv);
1938 if (rc)
1940 log_error ("`%s': %s\n", *argv, gpg_strerror (rc));
1941 http_release_parsed_uri (uri);
1942 return 1;
1945 printf ("Scheme: %s\n", uri->scheme);
1946 printf ("Host : %s\n", uri->host);
1947 printf ("Port : %u\n", uri->port);
1948 printf ("Path : %s\n", uri->path);
1949 for (r = uri->params; r; r = r->next)
1951 printf ("Params: %s", r->name);
1952 if (!r->no_value)
1954 printf ("=%s", r->value);
1955 if (strlen (r->value) != r->valuelen)
1956 printf (" [real length=%d]", (int) r->valuelen);
1958 putchar ('\n');
1960 for (r = uri->query; r; r = r->next)
1962 printf ("Query : %s", r->name);
1963 if (!r->no_value)
1965 printf ("=%s", r->value);
1966 if (strlen (r->value) != r->valuelen)
1967 printf (" [real length=%d]", (int) r->valuelen);
1969 putchar ('\n');
1971 http_release_parsed_uri (uri);
1972 uri = NULL;
1974 rc = http_open_document (&hd, *argv, NULL,
1975 HTTP_FLAG_NO_SHUTDOWN | HTTP_FLAG_NEED_HEADER,
1976 NULL, tls_session);
1977 if (rc)
1979 log_error ("can't get `%s': %s\n", *argv, gpg_strerror (rc));
1980 return 1;
1982 log_info ("open_http_document succeeded; status=%u\n",
1983 http_get_status_code (hd));
1984 for (hdr = hd->headers; hdr; hdr = hdr->next)
1985 printf ("HDR: %s: %s\n", hdr->name, hdr->value);
1986 switch (http_get_status_code (hd))
1988 case 200:
1989 while ((c = P_ES(getc) (http_get_read_ptr (hd))) != EOF)
1990 putchar (c);
1991 break;
1992 case 301:
1993 case 302:
1994 printf ("Redirected to `%s'\n", http_get_header (hd, "Location"));
1995 break;
1997 http_close (hd, 0);
1999 #ifdef HTTP_USE_GNUTLS
2000 gnutls_deinit (tls_session);
2001 gnutls_certificate_free_credentials (certcred);
2002 gnutls_global_deinit ();
2003 #endif /*HTTP_USE_GNUTLS*/
2005 return 0;
2007 #endif /*TEST*/
2011 Local Variables:
2012 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"
2013 End: