2009-05-15 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / common / http.c
blob73a6cb8fb20eba0d067e83a6a56767eb6ef8bf70
1 /* http.c - HTTP protocol handler
2 * Copyright (C) 1999, 2001, 2002, 2003, 2004, 2006,
3 * 2009 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 #else
308 (void)cb;
309 #endif
314 /* Start a HTTP retrieval and return on success in R_HD a context
315 pointer for completing the the request and to wait for the
316 response. */
317 gpg_error_t
318 http_open (http_t *r_hd, http_req_t reqtype, const char *url,
319 const char *auth, unsigned int flags, const char *proxy,
320 void *tls_context)
322 gpg_error_t err;
323 http_t hd;
325 *r_hd = NULL;
327 if (!(reqtype == HTTP_REQ_GET || reqtype == HTTP_REQ_POST))
328 return gpg_error (GPG_ERR_INV_ARG);
330 /* Create the handle. */
331 hd = xtrycalloc (1, sizeof *hd);
332 if (!hd)
333 return gpg_error_from_syserror ();
334 hd->sock = -1;
335 hd->req_type = reqtype;
336 hd->flags = flags;
337 hd->tls_context = tls_context;
339 err = http_parse_uri (&hd->uri, url);
340 if (!err)
341 err = send_request (hd, auth, proxy);
343 if (err)
345 if (!hd->fp_read && !hd->fp_write && hd->sock != -1)
346 sock_close (hd->sock);
347 if (hd->fp_read)
348 P_ES(fclose) (hd->fp_read);
349 if (hd->fp_write)
350 P_ES(fclose) (hd->fp_write);
351 http_release_parsed_uri (hd->uri);
352 xfree (hd);
354 else
355 *r_hd = hd;
356 return err;
360 void
361 http_start_data (http_t hd)
363 if (!hd->in_data)
365 #ifdef HTTP_USE_ESTREAM
366 es_fputs ("\r\n", hd->fp_write);
367 es_fflush (hd->fp_write);
368 #else
369 fflush (hd->fp_write);
370 write_server (hd->sock, "\r\n", 2);
371 #endif
372 hd->in_data = 1;
374 else
375 P_ES(fflush) (hd->fp_write);
379 gpg_error_t
380 http_wait_response (http_t hd)
382 gpg_error_t err;
384 /* Make sure that we are in the data. */
385 http_start_data (hd);
387 /* We dup the socket, to cope with the fact that fclose closes the
388 underlying socket. In TLS mode we don't do that because we can't
389 close the socket gnutls is working on; instead we make sure that
390 the fclose won't close the socket in this case. */
391 #ifdef HTTP_USE_ESTREAM
392 if (hd->write_cookie)
394 /* The write cookie is only set in the TLS case. */
395 cookie_t cookie = hd->write_cookie;
396 cookie->keep_socket = 1;
398 else
399 #endif /*HTTP_USE_ESTREAM*/
401 #ifdef HAVE_W32_SYSTEM
402 HANDLE handle = (HANDLE)hd->sock;
403 if (!DuplicateHandle (GetCurrentProcess(), handle,
404 GetCurrentProcess(), &handle, 0,
405 TRUE, DUPLICATE_SAME_ACCESS ))
406 return gpg_error_from_syserror ();
407 hd->sock = (int)handle;
408 #else
409 hd->sock = dup (hd->sock);
410 #endif
411 if (hd->sock == -1)
412 return gpg_error_from_syserror ();
414 P_ES(fclose) (hd->fp_write);
415 hd->fp_write = NULL;
416 #ifdef HTTP_USE_ESTREAM
417 hd->write_cookie = NULL;
418 #endif
420 if (!(hd->flags & HTTP_FLAG_NO_SHUTDOWN))
421 shutdown (hd->sock, 1);
422 hd->in_data = 0;
424 #ifdef HTTP_USE_ESTREAM
426 cookie_t cookie;
428 cookie = xtrycalloc (1, sizeof *cookie);
429 if (!cookie)
430 return gpg_error_from_syserror ();
431 cookie->fd = hd->sock;
432 if (hd->uri->use_tls)
433 cookie->tls_session = hd->tls_context;
435 hd->fp_read = es_fopencookie (cookie, "r", cookie_functions);
436 if (!hd->fp_read)
438 xfree (cookie);
439 return gpg_error_from_syserror ();
442 #else /*!HTTP_USE_ESTREAM*/
443 hd->fp_read = fdopen (hd->sock, "r");
444 if (!hd->fp_read)
445 return gpg_error_from_syserror ();
446 #endif /*!HTTP_USE_ESTREAM*/
448 err = parse_response (hd);
449 return err;
453 /* Convenience function to send a request and wait for the response.
454 Closes the handle on error. If PROXY is not NULL, this value will
455 be used as an HTTP proxy and any enabled $http_proxy gets
456 ignored. */
457 gpg_error_t
458 http_open_document (http_t *r_hd, const char *document,
459 const char *auth, unsigned int flags, const char *proxy,
460 void *tls_context)
462 gpg_error_t err;
464 err = http_open (r_hd, HTTP_REQ_GET, document, auth, flags,
465 proxy, tls_context);
466 if (err)
467 return err;
469 err = http_wait_response (*r_hd);
470 if (err)
471 http_close (*r_hd, 0);
473 return err;
477 void
478 http_close (http_t hd, int keep_read_stream)
480 if (!hd)
481 return;
482 if (!hd->fp_read && !hd->fp_write && hd->sock != -1)
483 sock_close (hd->sock);
484 if (hd->fp_read && !keep_read_stream)
485 P_ES(fclose) (hd->fp_read);
486 if (hd->fp_write)
487 P_ES(fclose) (hd->fp_write);
488 http_release_parsed_uri (hd->uri);
489 while (hd->headers)
491 header_t tmp = hd->headers->next;
492 xfree (hd->headers->value);
493 xfree (hd->headers);
494 hd->headers = tmp;
496 xfree (hd->buffer);
497 xfree (hd);
501 #ifdef HTTP_USE_ESTREAM
502 estream_t
503 http_get_read_ptr (http_t hd)
505 return hd?hd->fp_read:NULL;
507 estream_t
508 http_get_write_ptr (http_t hd)
510 return hd?hd->fp_write:NULL;
512 #else /*!HTTP_USE_ESTREAM*/
513 FILE *
514 http_get_read_ptr (http_t hd)
516 return hd?hd->fp_read:NULL;
518 FILE *
519 http_get_write_ptr (http_t hd)
521 return hd?hd->fp_write:NULL;
523 #endif /*!HTTP_USE_ESTREAM*/
524 unsigned int
525 http_get_status_code (http_t hd)
527 return hd?hd->status_code:0;
533 * Parse an URI and put the result into the newly allocated RET_URI.
534 * The caller must always use release_parsed_uri() to releases the
535 * resources (even on error).
537 gpg_error_t
538 http_parse_uri (parsed_uri_t * ret_uri, const char *uri)
540 *ret_uri = xcalloc (1, sizeof **ret_uri + strlen (uri));
541 strcpy ((*ret_uri)->buffer, uri);
542 return do_parse_uri (*ret_uri, 0);
545 void
546 http_release_parsed_uri (parsed_uri_t uri)
548 if (uri)
550 uri_tuple_t r, r2;
552 for (r = uri->query; r; r = r2)
554 r2 = r->next;
555 xfree (r);
557 xfree (uri);
562 static gpg_error_t
563 do_parse_uri (parsed_uri_t uri, int only_local_part)
565 uri_tuple_t *tail;
566 char *p, *p2, *p3, *pp;
567 int n;
569 p = uri->buffer;
570 n = strlen (uri->buffer);
572 /* Initialize all fields to an empty string or an empty list. */
573 uri->scheme = uri->host = uri->path = p + n;
574 uri->port = 0;
575 uri->params = uri->query = NULL;
576 uri->use_tls = 0;
578 /* A quick validity check. */
579 if (strspn (p, VALID_URI_CHARS) != n)
580 return gpg_error (GPG_ERR_BAD_URI); /* Invalid characters found. */
582 if (!only_local_part)
584 /* Find the scheme. */
585 if (!(p2 = strchr (p, ':')) || p2 == p)
586 return gpg_error (GPG_ERR_BAD_URI); /* No scheme. */
587 *p2++ = 0;
588 for (pp=p; *pp; pp++)
589 *pp = tolower (*(unsigned char*)pp);
590 uri->scheme = p;
591 if (!strcmp (uri->scheme, "http"))
592 uri->port = 80;
593 #ifdef HTTP_USE_GNUTLS
594 else if (!strcmp (uri->scheme, "https"))
596 uri->port = 443;
597 uri->use_tls = 1;
599 #endif
600 else
601 return gpg_error (GPG_ERR_INV_URI); /* Unsupported scheme */
603 p = p2;
605 /* Find the hostname */
606 if (*p != '/')
607 return gpg_error (GPG_ERR_INV_URI); /* Does not start with a slash. */
609 p++;
610 if (*p == '/') /* There seems to be a hostname. */
612 p++;
613 if ((p2 = strchr (p, '/')))
614 *p2++ = 0;
616 /* Check for username/password encoding */
617 if ((p3 = strchr (p, '@')))
619 uri->auth = p;
620 *p3++ = '\0';
621 p = p3;
624 for (pp=p; *pp; pp++)
625 *pp = tolower (*(unsigned char*)pp);
627 /* Handle an IPv6 literal */
628 if( *p == '[' && (p3=strchr( p, ']' )) )
630 *p3++ = '\0';
631 /* worst case, uri->host should have length 0, points to \0 */
632 uri->host = p + 1;
633 p = p3;
635 else
636 uri->host = p;
638 if ((p3 = strchr (p, ':')))
640 *p3++ = '\0';
641 uri->port = atoi (p3);
644 if ((n = remove_escapes (uri->host)) < 0)
645 return gpg_error (GPG_ERR_BAD_URI);
646 if (n != strlen (uri->host))
647 return gpg_error (GPG_ERR_BAD_URI); /* Hostname incudes a Nul. */
648 p = p2 ? p2 : NULL;
650 } /* End global URI part. */
652 /* Parse the pathname part */
653 if (!p || !*p)
654 return 0; /* We don't have a path. Okay. */
656 /* TODO: Here we have to check params. */
658 /* Do we have a query part? */
659 if ((p2 = strchr (p, '?')))
660 *p2++ = 0;
662 uri->path = p;
663 if ((n = remove_escapes (p)) < 0)
664 return gpg_error (GPG_ERR_BAD_URI);
665 if (n != strlen (p))
666 return gpg_error (GPG_ERR_BAD_URI); /* Path includes a Nul. */
667 p = p2 ? p2 : NULL;
669 if (!p || !*p)
670 return 0; /* We don't have a query string. Okay. */
672 /* Now parse the query string. */
673 tail = &uri->query;
674 for (;;)
676 uri_tuple_t elem;
678 if ((p2 = strchr (p, '&')))
679 *p2++ = 0;
680 if (!(elem = parse_tuple (p)))
681 return gpg_error (GPG_ERR_BAD_URI);
682 *tail = elem;
683 tail = &elem->next;
685 if (!p2)
686 break; /* Ready. */
687 p = p2;
690 return 0;
695 * Remove all %xx escapes; this is done in-place. Returns: New length
696 * of the string.
698 static int
699 remove_escapes (char *string)
701 int n = 0;
702 unsigned char *p, *s;
704 for (p = s = (unsigned char*)string; *s; s++)
706 if (*s == '%')
708 if (s[1] && s[2] && isxdigit (s[1]) && isxdigit (s[2]))
710 s++;
711 *p = *s >= '0' && *s <= '9' ? *s - '0' :
712 *s >= 'A' && *s <= 'F' ? *s - 'A' + 10 : *s - 'a' + 10;
713 *p <<= 4;
714 s++;
715 *p |= *s >= '0' && *s <= '9' ? *s - '0' :
716 *s >= 'A' && *s <= 'F' ? *s - 'A' + 10 : *s - 'a' + 10;
717 p++;
718 n++;
720 else
722 *p++ = *s++;
723 if (*s)
724 *p++ = *s++;
725 if (*s)
726 *p++ = *s++;
727 if (*s)
728 *p = 0;
729 return -1; /* Bad URI. */
732 else
734 *p++ = *s;
735 n++;
738 *p = 0; /* Make sure to keep a string terminator. */
739 return n;
743 static int
744 insert_escapes (char *buffer, const char *string,
745 const char *special)
747 const unsigned char *s = (const unsigned char*)string;
748 int n = 0;
750 for (; *s; s++)
752 if (strchr (VALID_URI_CHARS, *s) && !strchr (special, *s))
754 if (buffer)
755 *(unsigned char*)buffer++ = *s;
756 n++;
758 else
760 if (buffer)
762 sprintf (buffer, "%%%02X", *s);
763 buffer += 3;
765 n += 3;
768 return n;
772 /* Allocate a new string from STRING using standard HTTP escaping as
773 well as escaping of characters given in SPECIALS. A common pattern
774 for SPECIALS is "%;?&=". However it depends on the needs, for
775 example "+" and "/: often needs to be escaped too. Returns NULL on
776 failure and sets ERRNO. */
777 char *
778 http_escape_string (const char *string, const char *specials)
780 int n;
781 char *buf;
783 n = insert_escapes (NULL, string, specials);
784 buf = xtrymalloc (n+1);
785 if (buf)
787 insert_escapes (buf, string, specials);
788 buf[n] = 0;
790 return buf;
795 static uri_tuple_t
796 parse_tuple (char *string)
798 char *p = string;
799 char *p2;
800 int n;
801 uri_tuple_t tuple;
803 if ((p2 = strchr (p, '=')))
804 *p2++ = 0;
805 if ((n = remove_escapes (p)) < 0)
806 return NULL; /* Bad URI. */
807 if (n != strlen (p))
808 return NULL; /* Name with a Nul in it. */
809 tuple = xtrycalloc (1, sizeof *tuple);
810 if (!tuple)
811 return NULL; /* Out of core. */
812 tuple->name = p;
813 if (!p2) /* We have only the name, so we assume an empty value string. */
815 tuple->value = p + strlen (p);
816 tuple->valuelen = 0;
817 tuple->no_value = 1; /* Explicitly mark that we have seen no '='. */
819 else /* Name and value. */
821 if ((n = remove_escapes (p2)) < 0)
823 xfree (tuple);
824 return NULL; /* Bad URI. */
826 tuple->value = p2;
827 tuple->valuelen = n;
829 return tuple;
834 * Send a HTTP request to the server
835 * Returns 0 if the request was successful
837 static gpg_error_t
838 send_request (http_t hd, const char *auth, const char *proxy)
840 gnutls_session_t tls_session;
841 gpg_error_t err;
842 const char *server;
843 char *request, *p;
844 unsigned short port;
845 const char *http_proxy = NULL;
846 char *proxy_authstr = NULL;
847 char *authstr = NULL;
848 int save_errno;
850 tls_session = hd->tls_context;
851 if (hd->uri->use_tls && !tls_session)
853 log_error ("TLS requested but no GNUTLS context provided\n");
854 return gpg_error (GPG_ERR_INTERNAL);
857 server = *hd->uri->host ? hd->uri->host : "localhost";
858 port = hd->uri->port ? hd->uri->port : 80;
860 if ( (proxy && *proxy)
861 || ( (hd->flags & HTTP_FLAG_TRY_PROXY)
862 && (http_proxy = getenv (HTTP_PROXY_ENV))
863 && *http_proxy ))
865 parsed_uri_t uri;
867 if (proxy)
868 http_proxy = proxy;
870 err = http_parse_uri (&uri, http_proxy);
871 if (err)
873 log_error ("invalid HTTP proxy (%s): %s\n",
874 http_proxy, gpg_strerror (err));
875 http_release_parsed_uri (uri);
876 return gpg_error (GPG_ERR_CONFIGURATION);
880 if (uri->auth)
882 remove_escapes (uri->auth);
883 proxy_authstr = make_header_line ("Proxy-Authorization: Basic ",
884 "\r\n",
885 uri->auth, strlen(uri->auth));
886 if (!proxy_authstr)
888 err = gpg_error_from_syserror ();
889 http_release_parsed_uri (uri);
890 return err;
894 hd->sock = connect_server (*uri->host ? uri->host : "localhost",
895 uri->port ? uri->port : 80,
896 hd->flags, hd->uri->scheme);
897 save_errno = errno;
898 http_release_parsed_uri (uri);
900 else
902 hd->sock = connect_server (server, port, hd->flags, hd->uri->scheme);
903 save_errno = errno;
906 if (hd->sock == -1)
908 xfree (proxy_authstr);
909 return (save_errno
910 ? gpg_error_from_errno (save_errno)
911 : gpg_error (GPG_ERR_NOT_FOUND));
914 #ifdef HTTP_USE_GNUTLS
915 if (hd->uri->use_tls)
917 int rc;
919 gnutls_transport_set_ptr (tls_session, (gnutls_transport_ptr_t)hd->sock);
922 rc = gnutls_handshake (tls_session);
924 while (rc == GNUTLS_E_INTERRUPTED || rc == GNUTLS_E_AGAIN);
925 if (rc < 0)
927 log_info ("TLS handshake failed: %s\n", gnutls_strerror (rc));
928 xfree (proxy_authstr);
929 return gpg_error (GPG_ERR_NETWORK);
932 if (tls_callback)
934 err = tls_callback (hd, tls_session, 0);
935 if (err)
937 log_info ("TLS connection authentication failed: %s\n",
938 gpg_strerror (err));
939 xfree (proxy_authstr);
940 return err;
944 #endif /*HTTP_USE_GNUTLS*/
946 if (auth || hd->uri->auth)
948 char *myauth;
950 if (auth)
952 myauth = xtrystrdup (auth);
953 if (!myauth)
955 xfree (proxy_authstr);
956 return gpg_error_from_syserror ();
958 remove_escapes (myauth);
960 else
962 remove_escapes (hd->uri->auth);
963 myauth = hd->uri->auth;
966 authstr = make_header_line ("Authorization: Basic %s", "\r\n",
967 myauth, strlen (myauth));
968 if (auth)
969 xfree (myauth);
971 if (!authstr)
973 xfree (proxy_authstr);
974 return gpg_error_from_syserror ();
978 p = build_rel_path (hd->uri);
979 if (!p)
980 return gpg_error_from_syserror ();
982 request = xtrymalloc (2 * strlen (server)
983 + strlen (p)
984 + (authstr?strlen(authstr):0)
985 + (proxy_authstr?strlen(proxy_authstr):0)
986 + 100);
987 if (!request)
989 err = gpg_error_from_syserror ();
990 xfree (p);
991 xfree (authstr);
992 xfree (proxy_authstr);
993 return err;
996 if (http_proxy && *http_proxy)
998 sprintf (request, "%s http://%s:%hu%s%s HTTP/1.0\r\n%s%s",
999 hd->req_type == HTTP_REQ_GET ? "GET" :
1000 hd->req_type == HTTP_REQ_HEAD ? "HEAD" :
1001 hd->req_type == HTTP_REQ_POST ? "POST" : "OOPS",
1002 server, port, *p == '/' ? "" : "/", p,
1003 authstr ? authstr : "",
1004 proxy_authstr ? proxy_authstr : "");
1006 else
1008 char portstr[35];
1010 if (port == 80)
1011 *portstr = 0;
1012 else
1013 sprintf (portstr, ":%u", port);
1015 sprintf (request, "%s %s%s HTTP/1.0\r\nHost: %s%s\r\n%s",
1016 hd->req_type == HTTP_REQ_GET ? "GET" :
1017 hd->req_type == HTTP_REQ_HEAD ? "HEAD" :
1018 hd->req_type == HTTP_REQ_POST ? "POST" : "OOPS",
1019 *p == '/' ? "" : "/", p, server, portstr,
1020 authstr? authstr:"");
1022 xfree (p);
1025 #ifdef HTTP_USE_ESTREAM
1026 /* First setup estream so that we can write even the first line
1027 using estream. This is also required for the sake of gnutls. */
1029 cookie_t cookie;
1031 cookie = xtrycalloc (1, sizeof *cookie);
1032 if (!cookie)
1034 err = gpg_error_from_syserror ();
1035 goto leave;
1037 cookie->fd = hd->sock;
1038 if (hd->uri->use_tls)
1040 cookie->tls_session = tls_session;
1041 hd->write_cookie = cookie;
1044 hd->fp_write = es_fopencookie (cookie, "w", cookie_functions);
1045 if (!hd->fp_write)
1047 xfree (cookie);
1048 err = gpg_error_from_syserror ();
1050 else if (es_fputs (request, hd->fp_write) || es_fflush (hd->fp_write))
1051 err = gpg_error_from_syserror ();
1052 else
1053 err = 0;
1056 leave:
1058 #else /*!HTTP_USE_ESTREAM*/
1059 /* We send out the start of the request through our own send
1060 function and only then assign a stdio stream. This allows for
1061 better error reporting that through standard stdio means. */
1062 err = write_server (hd->sock, request, strlen (request));
1063 if (!err)
1065 hd->fp_write = fdopen (hd->sock, "w");
1066 if (!hd->fp_write)
1067 err = gpg_error_from_syserror ();
1069 #endif /*!HTTP_USE_ESTREAM*/
1071 xfree (request);
1072 xfree (authstr);
1073 xfree (proxy_authstr);
1075 return err;
1080 * Build the relative path from the parsed URI. Minimal
1081 * implementation. May return NULL in case of memory failure; errno
1082 * is then set accordingly.
1084 static char *
1085 build_rel_path (parsed_uri_t uri)
1087 uri_tuple_t r;
1088 char *rel_path, *p;
1089 int n;
1091 /* Count the needed space. */
1092 n = insert_escapes (NULL, uri->path, "%;?&");
1093 /* TODO: build params. */
1094 for (r = uri->query; r; r = r->next)
1096 n++; /* '?'/'&' */
1097 n += insert_escapes (NULL, r->name, "%;?&=");
1098 if (!r->no_value)
1100 n++; /* '=' */
1101 n += insert_escapes (NULL, r->value, "%;?&=");
1104 n++;
1106 /* Now allocate and copy. */
1107 p = rel_path = xtrymalloc (n);
1108 if (!p)
1109 return NULL;
1110 n = insert_escapes (p, uri->path, "%;?&");
1111 p += n;
1112 /* TODO: add params. */
1113 for (r = uri->query; r; r = r->next)
1115 *p++ = r == uri->query ? '?' : '&';
1116 n = insert_escapes (p, r->name, "%;?&=");
1117 p += n;
1118 if (!r->no_value)
1120 *p++ = '=';
1121 /* TODO: Use valuelen. */
1122 n = insert_escapes (p, r->value, "%;?&=");
1123 p += n;
1126 *p = 0;
1127 return rel_path;
1133 Same as fgets() but if the buffer is too short a larger one will be
1134 allocated up to some limit *MAX_LENGTH. A line is considered a
1135 byte stream ending in a LF. Returns the length of the line. EOF is
1136 indicated by a line of length zero. The last LF may be missing due
1137 to an EOF. If MAX_LENGTH is zero on return, the line has been
1138 truncated. If the returned buffer is NULL, not enough memory was
1139 enable to increase it, the return value will also be 0 and some
1140 bytes might have been lost which should be no problem becuase
1141 out-of-memory is pretty fatal for most applications.
1143 If a line has been truncated, the file pointer is internally moved
1144 forward to the end of the line.
1146 Note: The returned buffer is allocated with enough extra space to
1147 append a CR,LF,Nul
1149 static size_t
1150 my_read_line (
1151 #ifdef HTTP_USE_ESTREAM
1152 estream_t fp,
1153 #else
1154 FILE *fp,
1155 #endif
1156 char **addr_of_buffer,
1157 size_t *length_of_buffer, size_t *max_length)
1159 int c;
1160 char *buffer = *addr_of_buffer;
1161 size_t length = *length_of_buffer;
1162 size_t nbytes = 0;
1163 size_t maxlen = *max_length;
1164 char *p;
1166 if (!buffer) /* Must allocate a new buffer. */
1168 length = 256;
1169 buffer = xtrymalloc (length);
1170 *addr_of_buffer = buffer;
1171 if (!buffer)
1173 *length_of_buffer = *max_length = 0;
1174 return 0;
1176 *length_of_buffer = length;
1179 length -= 3; /* Reserve 3 bytes (cr,lf,eol). */
1180 p = buffer;
1181 while ((c = P_ES(getc) (fp)) != EOF)
1183 if (nbytes == length) /* Increase the buffer. */
1185 if (length > maxlen) /* Limit reached. */
1187 /* Skip the rest of the line. */
1188 while (c != '\n' && (c = P_ES(getc) (fp)) != EOF)
1190 *p++ = '\n'; /* Always append a LF (we reserved some space). */
1191 nbytes++;
1192 *max_length = 0; /* Indicate truncation */
1193 break; /*(the while loop)*/
1195 length += 3; /* Adjust for the reserved bytes. */
1196 length += length < 1024 ? 256 : 1024;
1197 *addr_of_buffer = xtryrealloc (buffer, length);
1198 if (!*addr_of_buffer)
1200 int save_errno = errno;
1201 xfree (buffer);
1202 *length_of_buffer = *max_length = 0;
1203 errno = save_errno;
1204 return 0;
1206 buffer = *addr_of_buffer;
1207 *length_of_buffer = length;
1208 length -= 3; /* And re-adjust for the reservation. */
1209 p = buffer + nbytes;
1211 *p++ = c;
1212 nbytes++;
1213 if (c == '\n')
1214 break;
1216 *p = 0; /* Make sure the line is a string. */
1218 return nbytes;
1222 /* Transform a header name into a standard capitalized format; e.g.
1223 "Content-Type". Conversion stops at the colon. As usual we don't
1224 use the localized versions of ctype.h. */
1225 static void
1226 capitalize_header_name (char *name)
1228 int first = 1;
1230 for (; *name && *name != ':'; name++)
1232 if (*name == '-')
1233 first = 1;
1234 else if (first)
1236 if (*name >= 'a' && *name <= 'z')
1237 *name = *name - 'a' + 'A';
1238 first = 0;
1240 else if (*name >= 'A' && *name <= 'Z')
1241 *name = *name - 'A' + 'a';
1246 /* Store an HTTP header line in LINE away. Line continuation is
1247 supported as well as merging of headers with the same name. This
1248 function may modify LINE. */
1249 static gpg_error_t
1250 store_header (http_t hd, char *line)
1252 size_t n;
1253 char *p, *value;
1254 header_t h;
1256 n = strlen (line);
1257 if (n && line[n-1] == '\n')
1259 line[--n] = 0;
1260 if (n && line[n-1] == '\r')
1261 line[--n] = 0;
1263 if (!n) /* we are never called to hit this. */
1264 return gpg_error (GPG_ERR_BUG);
1265 if (*line == ' ' || *line == '\t')
1267 /* Continuation. This won't happen too often as it is not
1268 recommended. We use a straightforward implementaion. */
1269 if (!hd->headers)
1270 return gpg_error (GPG_ERR_PROTOCOL_VIOLATION);
1271 n += strlen (hd->headers->value);
1272 p = xtrymalloc (n+1);
1273 if (!p)
1274 return gpg_error_from_syserror ();
1275 strcpy (stpcpy (p, hd->headers->value), line);
1276 xfree (hd->headers->value);
1277 hd->headers->value = p;
1278 return 0;
1281 capitalize_header_name (line);
1282 p = strchr (line, ':');
1283 if (!p)
1284 return gpg_error (GPG_ERR_PROTOCOL_VIOLATION);
1285 *p++ = 0;
1286 while (*p == ' ' || *p == '\t')
1287 p++;
1288 value = p;
1290 for (h=hd->headers; h; h = h->next)
1291 if ( !strcmp (h->name, line) )
1292 break;
1293 if (h)
1295 /* We have already seen a line with that name. Thus we assume
1296 it is a comma separated list and merge them. */
1297 p = xtrymalloc (strlen (h->value) + 1 + strlen (value)+ 1);
1298 if (!p)
1299 return gpg_error_from_syserror ();
1300 strcpy (stpcpy (stpcpy (p, h->value), ","), value);
1301 xfree (h->value);
1302 h->value = p;
1303 return 0;
1306 /* Append a new header. */
1307 h = xtrymalloc (sizeof *h + strlen (line));
1308 if (!h)
1309 return gpg_error_from_syserror ();
1310 strcpy (h->name, line);
1311 h->value = xtrymalloc (strlen (value)+1);
1312 if (!h->value)
1314 xfree (h);
1315 return gpg_error_from_syserror ();
1317 strcpy (h->value, value);
1318 h->next = hd->headers;
1319 hd->headers = h;
1321 return 0;
1325 /* Return the header NAME from the last response. The returned value
1326 is valid as along as HD has not been closed and no othe request has
1327 been send. If the header was not found, NULL is returned. Name
1328 must be canonicalized, that is the first letter of each dash
1329 delimited part must be uppercase and all other letters lowercase.
1330 Note that the context must have been opened with the
1331 HTTP_FLAG_NEED_HEADER. */
1332 const char *
1333 http_get_header (http_t hd, const char *name)
1335 header_t h;
1337 for (h=hd->headers; h; h = h->next)
1338 if ( !strcmp (h->name, name) )
1339 return h->value;
1340 return NULL;
1346 * Parse the response from a server.
1347 * Returns: Errorcode and sets some files in the handle
1349 static gpg_error_t
1350 parse_response (http_t hd)
1352 char *line, *p, *p2;
1353 size_t maxlen, len;
1355 /* Delete old header lines. */
1356 while (hd->headers)
1358 header_t tmp = hd->headers->next;
1359 xfree (hd->headers->value);
1360 xfree (hd->headers);
1361 hd->headers = tmp;
1364 /* Wait for the status line. */
1367 maxlen = MAX_LINELEN;
1368 len = my_read_line (hd->fp_read, &hd->buffer, &hd->buffer_size, &maxlen);
1369 line = hd->buffer;
1370 if (!line)
1371 return gpg_error_from_syserror (); /* Out of core. */
1372 if (!maxlen)
1373 return gpg_error (GPG_ERR_TRUNCATED); /* Line has been truncated. */
1374 if (!len)
1375 return gpg_error (GPG_ERR_EOF);
1376 if ( (hd->flags & HTTP_FLAG_LOG_RESP) )
1377 log_info ("RESP: `%.*s'\n",
1378 (int)strlen(line)-(*line&&line[1]?2:0),line);
1380 while (!*line);
1382 if ((p = strchr (line, '/')))
1383 *p++ = 0;
1384 if (!p || strcmp (line, "HTTP"))
1385 return 0; /* Assume http 0.9. */
1387 if ((p2 = strpbrk (p, " \t")))
1389 *p2++ = 0;
1390 p2 += strspn (p2, " \t");
1392 if (!p2)
1393 return 0; /* Also assume http 0.9. */
1394 p = p2;
1395 /* TODO: Add HTTP version number check. */
1396 if ((p2 = strpbrk (p, " \t")))
1397 *p2++ = 0;
1398 if (!isdigit ((unsigned int)p[0]) || !isdigit ((unsigned int)p[1])
1399 || !isdigit ((unsigned int)p[2]) || p[3])
1401 /* Malformed HTTP status code - assume http 0.9. */
1402 hd->is_http_0_9 = 1;
1403 hd->status_code = 200;
1404 return 0;
1406 hd->status_code = atoi (p);
1408 /* Skip all the header lines and wait for the empty line. */
1411 maxlen = MAX_LINELEN;
1412 len = my_read_line (hd->fp_read, &hd->buffer, &hd->buffer_size, &maxlen);
1413 line = hd->buffer;
1414 if (!line)
1415 return gpg_error_from_syserror (); /* Out of core. */
1416 /* Note, that we can silently ignore truncated lines. */
1417 if (!len)
1418 return gpg_error (GPG_ERR_EOF);
1419 /* Trim line endings of empty lines. */
1420 if ((*line == '\r' && line[1] == '\n') || *line == '\n')
1421 *line = 0;
1422 if ( (hd->flags & HTTP_FLAG_LOG_RESP) )
1423 log_info ("RESP: `%.*s'\n",
1424 (int)strlen(line)-(*line&&line[1]?2:0),line);
1425 if ( (hd->flags & HTTP_FLAG_NEED_HEADER) && *line )
1427 gpg_error_t err = store_header (hd, line);
1428 if (err)
1429 return err;
1432 while (len && *line);
1434 return 0;
1437 #if 0
1438 static int
1439 start_server ()
1441 struct sockaddr_in mya;
1442 struct sockaddr_in peer;
1443 int fd, client;
1444 fd_set rfds;
1445 int addrlen;
1446 int i;
1448 if ((fd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
1450 log_error ("socket() failed: %s\n", strerror (errno));
1451 return -1;
1453 i = 1;
1454 if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (byte *) & i, sizeof (i)))
1455 log_info ("setsockopt(SO_REUSEADDR) failed: %s\n", strerror (errno));
1457 mya.sin_family = AF_INET;
1458 memset (&mya.sin_addr, 0, sizeof (mya.sin_addr));
1459 mya.sin_port = htons (11371);
1461 if (bind (fd, (struct sockaddr *) &mya, sizeof (mya)))
1463 log_error ("bind to port 11371 failed: %s\n", strerror (errno));
1464 sock_close (fd);
1465 return -1;
1468 if (listen (fd, 5))
1470 log_error ("listen failed: %s\n", strerror (errno));
1471 sock_close (fd);
1472 return -1;
1475 for (;;)
1477 FD_ZERO (&rfds);
1478 FD_SET (fd, &rfds);
1480 if (select (fd + 1, &rfds, NULL, NULL, NULL) <= 0)
1481 continue; /* ignore any errors */
1483 if (!FD_ISSET (fd, &rfds))
1484 continue;
1486 addrlen = sizeof peer;
1487 client = accept (fd, (struct sockaddr *) &peer, &addrlen);
1488 if (client == -1)
1489 continue; /* oops */
1491 log_info ("connect from %s\n", inet_ntoa (peer.sin_addr));
1493 fflush (stdout);
1494 fflush (stderr);
1495 if (!fork ())
1497 int c;
1498 FILE *fp;
1500 fp = fdopen (client, "r");
1501 while ((c = getc (fp)) != EOF)
1502 putchar (c);
1503 fclose (fp);
1504 exit (0);
1506 sock_close (client);
1510 return 0;
1512 #endif
1514 /* Actually connect to a server. Returns the file descriptor or -1 on
1515 error. ERRNO is set on error. */
1516 static int
1517 connect_server (const char *server, unsigned short port,
1518 unsigned int flags, const char *srvtag)
1520 int sock = -1;
1521 int srvcount = 0;
1522 int hostfound = 0;
1523 int srv, connected;
1524 int last_errno = 0;
1525 struct srventry *serverlist = NULL;
1527 #ifdef HAVE_W32_SYSTEM
1528 unsigned long inaddr;
1530 #ifndef HTTP_NO_WSASTARTUP
1531 init_sockets ();
1532 #endif
1533 /* Win32 gethostbyname doesn't handle IP addresses internally, so we
1534 try inet_addr first on that platform only. */
1535 inaddr = inet_addr(server);
1536 if ( inaddr != INADDR_NONE )
1538 struct sockaddr_in addr;
1540 memset(&addr,0,sizeof(addr));
1542 sock = socket(AF_INET,SOCK_STREAM,0);
1543 if ( sock==INVALID_SOCKET )
1545 log_error("error creating socket: ec=%d\n",(int)WSAGetLastError());
1546 return -1;
1549 addr.sin_family = AF_INET;
1550 addr.sin_port = htons(port);
1551 memcpy (&addr.sin_addr,&inaddr,sizeof(inaddr));
1553 if (!connect (sock,(struct sockaddr *)&addr,sizeof(addr)) )
1554 return sock;
1555 sock_close(sock);
1556 return -1;
1558 #endif /*HAVE_W32_SYSTEM*/
1560 #ifdef USE_DNS_SRV
1561 /* Do the SRV thing */
1562 if ((flags & HTTP_FLAG_TRY_SRV) && srvtag)
1564 /* We're using SRV, so append the tags. */
1565 if (1+strlen (srvtag) + 6 + strlen (server) + 1 <= MAXDNAME)
1567 char srvname[MAXDNAME];
1569 stpcpy (stpcpy (stpcpy (stpcpy (srvname,"_"), srvtag),
1570 "._tcp."), server);
1571 srvcount = getsrv (srvname, &serverlist);
1574 #endif /*USE_DNS_SRV*/
1576 if (!serverlist)
1578 /* Either we're not using SRV, or the SRV lookup failed. Make
1579 up a fake SRV record. */
1580 serverlist = xtrycalloc (1, sizeof *serverlist);
1581 if (!serverlist)
1582 return -1; /* Out of core. */
1583 serverlist->port = port;
1584 strncpy (serverlist->target, server, MAXDNAME);
1585 serverlist->target[MAXDNAME-1] = '\0';
1586 srvcount = 1;
1589 #ifdef HAVE_GETADDRINFO
1590 connected = 0;
1591 for (srv=0; srv < srvcount && !connected; srv++)
1593 struct addrinfo hints, *res, *ai;
1594 char portstr[35];
1596 sprintf (portstr, "%hu", port);
1597 memset (&hints, 0, sizeof (hints));
1598 hints.ai_socktype = SOCK_STREAM;
1599 if (getaddrinfo (serverlist[srv].target, portstr, &hints, &res))
1600 continue; /* Not found - try next one. */
1601 hostfound = 1;
1603 for (ai = res; ai && !connected; ai = ai->ai_next)
1605 if (sock != -1)
1606 sock_close (sock);
1607 sock = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol);
1608 if (sock == -1)
1610 int save_errno = errno;
1611 log_error ("error creating socket: %s\n", strerror (errno));
1612 freeaddrinfo (res);
1613 xfree (serverlist);
1614 errno = save_errno;
1615 return -1;
1618 if (connect (sock, ai->ai_addr, ai->ai_addrlen))
1619 last_errno = errno;
1620 else
1621 connected = 1;
1623 freeaddrinfo (res);
1625 #else /* !HAVE_GETADDRINFO */
1626 connected = 0;
1627 for (srv=0; srv < srvcount && !connected; srv++)
1629 int i;
1630 struct hostent *host = NULL;
1631 struct sockaddr_in addr;
1633 /* Note: This code is not thread-safe. */
1635 memset (&addr, 0, sizeof (addr));
1636 host = gethostbyname (serverlist[srv].target);
1637 if (!host)
1638 continue;
1639 hostfound = 1;
1641 if (sock != -1)
1642 sock_close (sock);
1643 sock = socket (host->h_addrtype, SOCK_STREAM, 0);
1644 if (sock == -1)
1646 log_error (_("error creating socket: %s\n"), strerror (errno));
1647 xfree (serverlist);
1648 return -1;
1651 addr.sin_family = host->h_addrtype;
1652 if (addr.sin_family != AF_INET)
1654 log_error ("unknown address family for `%s'\n",
1655 serverlist[srv].target);
1656 xfree (serverlist);
1657 return -1;
1659 addr.sin_port = htons (serverlist[srv].port);
1660 if (host->h_length != 4)
1662 log_error ("illegal address length for `%s'\n",
1663 serverlist[srv].target);
1664 xfree (serverlist);
1665 return -1;
1668 /* Try all A records until one responds. */
1669 for (i = 0; host->h_addr_list[i] && !connected; i++)
1671 memcpy (&addr.sin_addr, host->h_addr_list[i], host->h_length);
1672 if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)))
1673 last_errno = errno;
1674 else
1676 connected = 1;
1677 break;
1681 #endif /* !HAVE_GETADDRINFO */
1683 xfree (serverlist);
1685 if (!connected)
1687 #ifdef HAVE_W32_SYSTEM
1688 log_error ("can't connect to `%s': %s%sec=%d\n",
1689 server,
1690 hostfound? "":_("host not found"),
1691 hostfound? "":" - ", (int)WSAGetLastError());
1692 #else
1693 log_error ("can't connect to `%s': %s\n",
1694 server,
1695 hostfound? strerror (last_errno):"host not found");
1696 #endif
1697 if (sock != -1)
1698 sock_close (sock);
1699 errno = last_errno;
1700 return -1;
1702 return sock;
1706 static gpg_error_t
1707 write_server (int sock, const char *data, size_t length)
1709 int nleft;
1711 nleft = length;
1712 while (nleft > 0)
1714 #ifdef HAVE_W32_SYSTEM
1715 int nwritten;
1717 nwritten = send (sock, data, nleft, 0);
1718 if ( nwritten == SOCKET_ERROR )
1720 log_info ("network write failed: ec=%d\n", (int)WSAGetLastError ());
1721 return gpg_error (GPG_ERR_NETWORK);
1723 #else /*!HAVE_W32_SYSTEM*/
1724 int nwritten = write (sock, data, nleft);
1725 if (nwritten == -1)
1727 if (errno == EINTR)
1728 continue;
1729 if (errno == EAGAIN)
1731 struct timeval tv;
1733 tv.tv_sec = 0;
1734 tv.tv_usec = 50000;
1735 select (0, NULL, NULL, NULL, &tv);
1736 continue;
1738 log_info ("network write failed: %s\n", strerror (errno));
1739 return gpg_error_from_syserror ();
1741 #endif /*!HAVE_W32_SYSTEM*/
1742 nleft -= nwritten;
1743 data += nwritten;
1746 return 0;
1751 #ifdef HTTP_USE_ESTREAM
1752 /* Read handler for estream. */
1753 static ssize_t
1754 cookie_read (void *cookie, void *buffer, size_t size)
1756 cookie_t c = cookie;
1757 int nread;
1759 #ifdef HTTP_USE_GNUTLS
1760 if (c->tls_session)
1762 again:
1763 nread = gnutls_record_recv (c->tls_session, buffer, size);
1764 if (nread < 0)
1766 if (nread == GNUTLS_E_INTERRUPTED)
1767 goto again;
1768 if (nread == GNUTLS_E_AGAIN)
1770 struct timeval tv;
1772 tv.tv_sec = 0;
1773 tv.tv_usec = 50000;
1774 select (0, NULL, NULL, NULL, &tv);
1775 goto again;
1777 if (nread == GNUTLS_E_REHANDSHAKE)
1778 goto again; /* A client is allowed to just ignore this request. */
1779 log_info ("TLS network read failed: %s\n", gnutls_strerror (nread));
1780 errno = EIO;
1781 return -1;
1784 else
1785 #endif /*HTTP_USE_GNUTLS*/
1789 #ifdef HAVE_W32_SYSTEM
1790 /* Under Windows we need to use recv for a socket. */
1791 nread = recv (c->fd, buffer, size, 0);
1792 #else
1793 nread = read (c->fd, buffer, size);
1794 #endif
1796 while (nread == -1 && errno == EINTR);
1799 return nread;
1802 /* Write handler for estream. */
1803 static ssize_t
1804 cookie_write (void *cookie, const void *buffer, size_t size)
1806 cookie_t c = cookie;
1807 int nwritten = 0;
1809 #ifdef HTTP_USE_GNUTLS
1810 if (c->tls_session)
1812 int nleft = size;
1813 while (nleft > 0)
1815 nwritten = gnutls_record_send (c->tls_session, buffer, nleft);
1816 if (nwritten <= 0)
1818 if (nwritten == GNUTLS_E_INTERRUPTED)
1819 continue;
1820 if (nwritten == GNUTLS_E_AGAIN)
1822 struct timeval tv;
1824 tv.tv_sec = 0;
1825 tv.tv_usec = 50000;
1826 select (0, NULL, NULL, NULL, &tv);
1827 continue;
1829 log_info ("TLS network write failed: %s\n",
1830 gnutls_strerror (nwritten));
1831 errno = EIO;
1832 return -1;
1834 nleft -= nwritten;
1835 buffer += nwritten;
1838 else
1839 #endif /*HTTP_USE_GNUTLS*/
1841 if ( write_server (c->fd, buffer, size) )
1843 errno = EIO;
1844 nwritten = -1;
1846 else
1847 nwritten = size;
1850 return nwritten;
1853 /* Close handler for estream. */
1854 static int
1855 cookie_close (void *cookie)
1857 cookie_t c = cookie;
1859 if (!c)
1860 return 0;
1862 #ifdef HTTP_USE_GNUTLS
1863 if (c->tls_session && !c->keep_socket)
1865 gnutls_bye (c->tls_session, GNUTLS_SHUT_RDWR);
1867 #endif /*HTTP_USE_GNUTLS*/
1868 if (c->fd != -1 && !c->keep_socket)
1869 sock_close (c->fd);
1871 xfree (c);
1872 return 0;
1874 #endif /*HTTP_USE_ESTREAM*/
1879 /**** Test code ****/
1880 #ifdef TEST
1882 static gpg_error_t
1883 verify_callback (http_t hd, void *tls_context, int reserved)
1885 log_info ("verification of certificates skipped\n");
1886 return 0;
1891 /* static void */
1892 /* my_gnutls_log (int level, const char *text) */
1893 /* { */
1894 /* fprintf (stderr, "gnutls:L%d: %s", level, text); */
1895 /* } */
1898 main (int argc, char **argv)
1900 int rc;
1901 parsed_uri_t uri;
1902 uri_tuple_t r;
1903 http_t hd;
1904 int c;
1905 gnutls_session_t tls_session = NULL;
1906 #ifdef HTTP_USE_GNUTLS
1907 gnutls_certificate_credentials certcred;
1908 const int certprio[] = { GNUTLS_CRT_X509, 0 };
1909 #endif /*HTTP_USE_GNUTLS*/
1910 header_t hdr;
1912 #ifdef HTTP_USE_ESTREAM
1913 es_init ();
1914 #endif
1915 log_set_prefix ("http-test", 1 | 4);
1916 if (argc == 1)
1918 /*start_server (); */
1919 return 0;
1922 if (argc != 2)
1924 fprintf (stderr, "usage: http-test uri\n");
1925 return 1;
1927 argc--;
1928 argv++;
1930 #ifdef HTTP_USE_GNUTLS
1931 rc = gnutls_global_init ();
1932 if (rc)
1933 log_error ("gnutls_global_init failed: %s\n", gnutls_strerror (rc));
1934 rc = gnutls_certificate_allocate_credentials (&certcred);
1935 if (rc)
1936 log_error ("gnutls_certificate_allocate_credentials failed: %s\n",
1937 gnutls_strerror (rc));
1938 /* rc = gnutls_certificate_set_x509_trust_file */
1939 /* (certcred, "ca.pem", GNUTLS_X509_FMT_PEM); */
1940 /* if (rc) */
1941 /* log_error ("gnutls_certificate_set_x509_trust_file failed: %s\n", */
1942 /* gnutls_strerror (rc)); */
1943 rc = gnutls_init (&tls_session, GNUTLS_CLIENT);
1944 if (rc)
1945 log_error ("gnutls_init failed: %s\n", gnutls_strerror (rc));
1946 rc = gnutls_set_default_priority (tls_session);
1947 if (rc)
1948 log_error ("gnutls_set_default_priority failed: %s\n",
1949 gnutls_strerror (rc));
1950 rc = gnutls_certificate_type_set_priority (tls_session, certprio);
1951 if (rc)
1952 log_error ("gnutls_certificate_type_set_priority failed: %s\n",
1953 gnutls_strerror (rc));
1954 rc = gnutls_credentials_set (tls_session, GNUTLS_CRD_CERTIFICATE, certcred);
1955 if (rc)
1956 log_error ("gnutls_credentials_set failed: %s\n", gnutls_strerror (rc));
1957 /* gnutls_global_set_log_function (my_gnutls_log); */
1958 /* gnutls_global_set_log_level (4); */
1960 http_register_tls_callback (verify_callback);
1961 #endif /*HTTP_USE_GNUTLS*/
1963 rc = http_parse_uri (&uri, *argv);
1964 if (rc)
1966 log_error ("`%s': %s\n", *argv, gpg_strerror (rc));
1967 http_release_parsed_uri (uri);
1968 return 1;
1971 printf ("Scheme: %s\n", uri->scheme);
1972 printf ("Host : %s\n", uri->host);
1973 printf ("Port : %u\n", uri->port);
1974 printf ("Path : %s\n", uri->path);
1975 for (r = uri->params; r; r = r->next)
1977 printf ("Params: %s", r->name);
1978 if (!r->no_value)
1980 printf ("=%s", r->value);
1981 if (strlen (r->value) != r->valuelen)
1982 printf (" [real length=%d]", (int) r->valuelen);
1984 putchar ('\n');
1986 for (r = uri->query; r; r = r->next)
1988 printf ("Query : %s", r->name);
1989 if (!r->no_value)
1991 printf ("=%s", r->value);
1992 if (strlen (r->value) != r->valuelen)
1993 printf (" [real length=%d]", (int) r->valuelen);
1995 putchar ('\n');
1997 http_release_parsed_uri (uri);
1998 uri = NULL;
2000 rc = http_open_document (&hd, *argv, NULL,
2001 HTTP_FLAG_NO_SHUTDOWN | HTTP_FLAG_NEED_HEADER,
2002 NULL, tls_session);
2003 if (rc)
2005 log_error ("can't get `%s': %s\n", *argv, gpg_strerror (rc));
2006 return 1;
2008 log_info ("open_http_document succeeded; status=%u\n",
2009 http_get_status_code (hd));
2010 for (hdr = hd->headers; hdr; hdr = hdr->next)
2011 printf ("HDR: %s: %s\n", hdr->name, hdr->value);
2012 switch (http_get_status_code (hd))
2014 case 200:
2015 while ((c = P_ES(getc) (http_get_read_ptr (hd))) != EOF)
2016 putchar (c);
2017 break;
2018 case 301:
2019 case 302:
2020 printf ("Redirected to `%s'\n", http_get_header (hd, "Location"));
2021 break;
2023 http_close (hd, 0);
2025 #ifdef HTTP_USE_GNUTLS
2026 gnutls_deinit (tls_session);
2027 gnutls_certificate_free_credentials (certcred);
2028 gnutls_global_deinit ();
2029 #endif /*HTTP_USE_GNUTLS*/
2031 return 0;
2033 #endif /*TEST*/
2037 Local Variables:
2038 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"
2039 End: