agent/
[gnupg.git] / common / http.c
blobc12bd2b3e4c41addc442803634ce029673066d73
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, const char *auth,const char *proxy,
132 const char *srvtag,strlist_t headers);
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, const char *srvtag,strlist_t headers)
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, srvtag, headers);
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, const char *srvtag,strlist_t headers)
462 gpg_error_t err;
464 err = http_open (r_hd, HTTP_REQ_GET, document, auth, flags,
465 proxy, tls_context, srvtag, headers);
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,
839 const char *proxy,const char *srvtag,strlist_t headers)
841 gnutls_session_t tls_session;
842 gpg_error_t err;
843 const char *server;
844 char *request, *p;
845 unsigned short port;
846 const char *http_proxy = NULL;
847 char *proxy_authstr = NULL;
848 char *authstr = NULL;
849 int save_errno;
851 tls_session = hd->tls_context;
852 if (hd->uri->use_tls && !tls_session)
854 log_error ("TLS requested but no GNUTLS context provided\n");
855 return gpg_error (GPG_ERR_INTERNAL);
858 server = *hd->uri->host ? hd->uri->host : "localhost";
859 port = hd->uri->port ? hd->uri->port : 80;
861 if ( (proxy && *proxy)
862 || ( (hd->flags & HTTP_FLAG_TRY_PROXY)
863 && (http_proxy = getenv (HTTP_PROXY_ENV))
864 && *http_proxy ))
866 parsed_uri_t uri;
868 if (proxy)
869 http_proxy = proxy;
871 err = http_parse_uri (&uri, http_proxy);
872 if (err)
874 log_error ("invalid HTTP proxy (%s): %s\n",
875 http_proxy, gpg_strerror (err));
876 http_release_parsed_uri (uri);
877 return gpg_error (GPG_ERR_CONFIGURATION);
881 if (uri->auth)
883 remove_escapes (uri->auth);
884 proxy_authstr = make_header_line ("Proxy-Authorization: Basic ",
885 "\r\n",
886 uri->auth, strlen(uri->auth));
887 if (!proxy_authstr)
889 err = gpg_error_from_syserror ();
890 http_release_parsed_uri (uri);
891 return err;
895 hd->sock = connect_server (*uri->host ? uri->host : "localhost",
896 uri->port ? uri->port : 80,
897 hd->flags, srvtag);
898 save_errno = errno;
899 http_release_parsed_uri (uri);
901 else
903 hd->sock = connect_server (server, port, hd->flags, srvtag);
904 save_errno = errno;
907 if (hd->sock == -1)
909 xfree (proxy_authstr);
910 return (save_errno
911 ? gpg_error_from_errno (save_errno)
912 : gpg_error (GPG_ERR_NOT_FOUND));
915 #ifdef HTTP_USE_GNUTLS
916 if (hd->uri->use_tls)
918 int rc;
920 gnutls_transport_set_ptr (tls_session, (gnutls_transport_ptr_t)hd->sock);
923 rc = gnutls_handshake (tls_session);
925 while (rc == GNUTLS_E_INTERRUPTED || rc == GNUTLS_E_AGAIN);
926 if (rc < 0)
928 log_info ("TLS handshake failed: %s\n", gnutls_strerror (rc));
929 xfree (proxy_authstr);
930 return gpg_error (GPG_ERR_NETWORK);
933 if (tls_callback)
935 err = tls_callback (hd, tls_session, 0);
936 if (err)
938 log_info ("TLS connection authentication failed: %s\n",
939 gpg_strerror (err));
940 xfree (proxy_authstr);
941 return err;
945 #endif /*HTTP_USE_GNUTLS*/
947 if (auth || hd->uri->auth)
949 char *myauth;
951 if (auth)
953 myauth = xtrystrdup (auth);
954 if (!myauth)
956 xfree (proxy_authstr);
957 return gpg_error_from_syserror ();
959 remove_escapes (myauth);
961 else
963 remove_escapes (hd->uri->auth);
964 myauth = hd->uri->auth;
967 authstr = make_header_line ("Authorization: Basic %s", "\r\n",
968 myauth, strlen (myauth));
969 if (auth)
970 xfree (myauth);
972 if (!authstr)
974 xfree (proxy_authstr);
975 return gpg_error_from_syserror ();
979 p = build_rel_path (hd->uri);
980 if (!p)
981 return gpg_error_from_syserror ();
983 request = xtrymalloc (2 * strlen (server)
984 + strlen (p)
985 + (authstr?strlen(authstr):0)
986 + (proxy_authstr?strlen(proxy_authstr):0)
987 + 100);
988 if (!request)
990 err = gpg_error_from_syserror ();
991 xfree (p);
992 xfree (authstr);
993 xfree (proxy_authstr);
994 return err;
997 if (http_proxy && *http_proxy)
999 sprintf (request, "%s http://%s:%hu%s%s HTTP/1.0\r\n%s%s",
1000 hd->req_type == HTTP_REQ_GET ? "GET" :
1001 hd->req_type == HTTP_REQ_HEAD ? "HEAD" :
1002 hd->req_type == HTTP_REQ_POST ? "POST" : "OOPS",
1003 server, port, *p == '/' ? "" : "/", p,
1004 authstr ? authstr : "",
1005 proxy_authstr ? proxy_authstr : "");
1007 else
1009 char portstr[35];
1011 if (port == 80)
1012 *portstr = 0;
1013 else
1014 sprintf (portstr, ":%u", port);
1016 sprintf (request, "%s %s%s HTTP/1.0\r\nHost: %s%s\r\n%s",
1017 hd->req_type == HTTP_REQ_GET ? "GET" :
1018 hd->req_type == HTTP_REQ_HEAD ? "HEAD" :
1019 hd->req_type == HTTP_REQ_POST ? "POST" : "OOPS",
1020 *p == '/' ? "" : "/", p, server, portstr,
1021 authstr? authstr:"");
1023 xfree (p);
1026 #ifdef HTTP_USE_ESTREAM
1027 /* First setup estream so that we can write even the first line
1028 using estream. This is also required for the sake of gnutls. */
1030 cookie_t cookie;
1032 cookie = xtrycalloc (1, sizeof *cookie);
1033 if (!cookie)
1035 err = gpg_error_from_syserror ();
1036 goto leave;
1038 cookie->fd = hd->sock;
1039 if (hd->uri->use_tls)
1041 cookie->tls_session = tls_session;
1042 hd->write_cookie = cookie;
1045 hd->fp_write = es_fopencookie (cookie, "w", cookie_functions);
1046 if (!hd->fp_write)
1048 xfree (cookie);
1049 err = gpg_error_from_syserror ();
1051 else if (es_fputs (request, hd->fp_write) || es_fflush (hd->fp_write))
1052 err = gpg_error_from_syserror ();
1053 else
1054 err = 0;
1056 if(err==0)
1057 for(;headers;headers=headers->next)
1059 if ((es_fputs (headers->d, hd->fp_write) || es_fflush (hd->fp_write))
1060 || (es_fputs("\r\n",hd->fp_write) || es_fflush(hd->fp_write)))
1062 err = gpg_error_from_syserror ();
1063 break;
1068 leave:
1070 #else /*!HTTP_USE_ESTREAM*/
1071 /* We send out the start of the request through our own send
1072 function and only then assign a stdio stream. This allows for
1073 better error reporting that through standard stdio means. */
1074 err = write_server (hd->sock, request, strlen (request));
1076 if(err==0)
1077 for(;headers;headers=headers->next)
1079 err = write_server( hd->sock, headers->d, strlen(headers->d) );
1080 if(err)
1081 break;
1082 err = write_server( hd->sock, "\r\n", 2 );
1083 if(err)
1084 break;
1087 if (!err)
1089 hd->fp_write = fdopen (hd->sock, "w");
1090 if (!hd->fp_write)
1091 err = gpg_error_from_syserror ();
1094 #endif /*!HTTP_USE_ESTREAM*/
1096 xfree (request);
1097 xfree (authstr);
1098 xfree (proxy_authstr);
1100 return err;
1105 * Build the relative path from the parsed URI. Minimal
1106 * implementation. May return NULL in case of memory failure; errno
1107 * is then set accordingly.
1109 static char *
1110 build_rel_path (parsed_uri_t uri)
1112 uri_tuple_t r;
1113 char *rel_path, *p;
1114 int n;
1116 /* Count the needed space. */
1117 n = insert_escapes (NULL, uri->path, "%;?&");
1118 /* TODO: build params. */
1119 for (r = uri->query; r; r = r->next)
1121 n++; /* '?'/'&' */
1122 n += insert_escapes (NULL, r->name, "%;?&=");
1123 if (!r->no_value)
1125 n++; /* '=' */
1126 n += insert_escapes (NULL, r->value, "%;?&=");
1129 n++;
1131 /* Now allocate and copy. */
1132 p = rel_path = xtrymalloc (n);
1133 if (!p)
1134 return NULL;
1135 n = insert_escapes (p, uri->path, "%;?&");
1136 p += n;
1137 /* TODO: add params. */
1138 for (r = uri->query; r; r = r->next)
1140 *p++ = r == uri->query ? '?' : '&';
1141 n = insert_escapes (p, r->name, "%;?&=");
1142 p += n;
1143 if (!r->no_value)
1145 *p++ = '=';
1146 /* TODO: Use valuelen. */
1147 n = insert_escapes (p, r->value, "%;?&=");
1148 p += n;
1151 *p = 0;
1152 return rel_path;
1158 Same as fgets() but if the buffer is too short a larger one will be
1159 allocated up to some limit *MAX_LENGTH. A line is considered a
1160 byte stream ending in a LF. Returns the length of the line. EOF is
1161 indicated by a line of length zero. The last LF may be missing due
1162 to an EOF. If MAX_LENGTH is zero on return, the line has been
1163 truncated. If the returned buffer is NULL, not enough memory was
1164 enable to increase it, the return value will also be 0 and some
1165 bytes might have been lost which should be no problem becuase
1166 out-of-memory is pretty fatal for most applications.
1168 If a line has been truncated, the file pointer is internally moved
1169 forward to the end of the line.
1171 Note: The returned buffer is allocated with enough extra space to
1172 append a CR,LF,Nul
1174 static size_t
1175 my_read_line (
1176 #ifdef HTTP_USE_ESTREAM
1177 estream_t fp,
1178 #else
1179 FILE *fp,
1180 #endif
1181 char **addr_of_buffer,
1182 size_t *length_of_buffer, size_t *max_length)
1184 int c;
1185 char *buffer = *addr_of_buffer;
1186 size_t length = *length_of_buffer;
1187 size_t nbytes = 0;
1188 size_t maxlen = *max_length;
1189 char *p;
1191 if (!buffer) /* Must allocate a new buffer. */
1193 length = 256;
1194 buffer = xtrymalloc (length);
1195 *addr_of_buffer = buffer;
1196 if (!buffer)
1198 *length_of_buffer = *max_length = 0;
1199 return 0;
1201 *length_of_buffer = length;
1204 length -= 3; /* Reserve 3 bytes (cr,lf,eol). */
1205 p = buffer;
1206 while ((c = P_ES(getc) (fp)) != EOF)
1208 if (nbytes == length) /* Increase the buffer. */
1210 if (length > maxlen) /* Limit reached. */
1212 /* Skip the rest of the line. */
1213 while (c != '\n' && (c = P_ES(getc) (fp)) != EOF)
1215 *p++ = '\n'; /* Always append a LF (we reserved some space). */
1216 nbytes++;
1217 *max_length = 0; /* Indicate truncation */
1218 break; /*(the while loop)*/
1220 length += 3; /* Adjust for the reserved bytes. */
1221 length += length < 1024 ? 256 : 1024;
1222 *addr_of_buffer = xtryrealloc (buffer, length);
1223 if (!*addr_of_buffer)
1225 int save_errno = errno;
1226 xfree (buffer);
1227 *length_of_buffer = *max_length = 0;
1228 errno = save_errno;
1229 return 0;
1231 buffer = *addr_of_buffer;
1232 *length_of_buffer = length;
1233 length -= 3; /* And re-adjust for the reservation. */
1234 p = buffer + nbytes;
1236 *p++ = c;
1237 nbytes++;
1238 if (c == '\n')
1239 break;
1241 *p = 0; /* Make sure the line is a string. */
1243 return nbytes;
1247 /* Transform a header name into a standard capitalized format; e.g.
1248 "Content-Type". Conversion stops at the colon. As usual we don't
1249 use the localized versions of ctype.h. */
1250 static void
1251 capitalize_header_name (char *name)
1253 int first = 1;
1255 for (; *name && *name != ':'; name++)
1257 if (*name == '-')
1258 first = 1;
1259 else if (first)
1261 if (*name >= 'a' && *name <= 'z')
1262 *name = *name - 'a' + 'A';
1263 first = 0;
1265 else if (*name >= 'A' && *name <= 'Z')
1266 *name = *name - 'A' + 'a';
1271 /* Store an HTTP header line in LINE away. Line continuation is
1272 supported as well as merging of headers with the same name. This
1273 function may modify LINE. */
1274 static gpg_error_t
1275 store_header (http_t hd, char *line)
1277 size_t n;
1278 char *p, *value;
1279 header_t h;
1281 n = strlen (line);
1282 if (n && line[n-1] == '\n')
1284 line[--n] = 0;
1285 if (n && line[n-1] == '\r')
1286 line[--n] = 0;
1288 if (!n) /* we are never called to hit this. */
1289 return gpg_error (GPG_ERR_BUG);
1290 if (*line == ' ' || *line == '\t')
1292 /* Continuation. This won't happen too often as it is not
1293 recommended. We use a straightforward implementaion. */
1294 if (!hd->headers)
1295 return gpg_error (GPG_ERR_PROTOCOL_VIOLATION);
1296 n += strlen (hd->headers->value);
1297 p = xtrymalloc (n+1);
1298 if (!p)
1299 return gpg_error_from_syserror ();
1300 strcpy (stpcpy (p, hd->headers->value), line);
1301 xfree (hd->headers->value);
1302 hd->headers->value = p;
1303 return 0;
1306 capitalize_header_name (line);
1307 p = strchr (line, ':');
1308 if (!p)
1309 return gpg_error (GPG_ERR_PROTOCOL_VIOLATION);
1310 *p++ = 0;
1311 while (*p == ' ' || *p == '\t')
1312 p++;
1313 value = p;
1315 for (h=hd->headers; h; h = h->next)
1316 if ( !strcmp (h->name, line) )
1317 break;
1318 if (h)
1320 /* We have already seen a line with that name. Thus we assume
1321 it is a comma separated list and merge them. */
1322 p = xtrymalloc (strlen (h->value) + 1 + strlen (value)+ 1);
1323 if (!p)
1324 return gpg_error_from_syserror ();
1325 strcpy (stpcpy (stpcpy (p, h->value), ","), value);
1326 xfree (h->value);
1327 h->value = p;
1328 return 0;
1331 /* Append a new header. */
1332 h = xtrymalloc (sizeof *h + strlen (line));
1333 if (!h)
1334 return gpg_error_from_syserror ();
1335 strcpy (h->name, line);
1336 h->value = xtrymalloc (strlen (value)+1);
1337 if (!h->value)
1339 xfree (h);
1340 return gpg_error_from_syserror ();
1342 strcpy (h->value, value);
1343 h->next = hd->headers;
1344 hd->headers = h;
1346 return 0;
1350 /* Return the header NAME from the last response. The returned value
1351 is valid as along as HD has not been closed and no othe request has
1352 been send. If the header was not found, NULL is returned. Name
1353 must be canonicalized, that is the first letter of each dash
1354 delimited part must be uppercase and all other letters lowercase.
1355 Note that the context must have been opened with the
1356 HTTP_FLAG_NEED_HEADER. */
1357 const char *
1358 http_get_header (http_t hd, const char *name)
1360 header_t h;
1362 for (h=hd->headers; h; h = h->next)
1363 if ( !strcmp (h->name, name) )
1364 return h->value;
1365 return NULL;
1371 * Parse the response from a server.
1372 * Returns: Errorcode and sets some files in the handle
1374 static gpg_error_t
1375 parse_response (http_t hd)
1377 char *line, *p, *p2;
1378 size_t maxlen, len;
1380 /* Delete old header lines. */
1381 while (hd->headers)
1383 header_t tmp = hd->headers->next;
1384 xfree (hd->headers->value);
1385 xfree (hd->headers);
1386 hd->headers = tmp;
1389 /* Wait for the status line. */
1392 maxlen = MAX_LINELEN;
1393 len = my_read_line (hd->fp_read, &hd->buffer, &hd->buffer_size, &maxlen);
1394 line = hd->buffer;
1395 if (!line)
1396 return gpg_error_from_syserror (); /* Out of core. */
1397 if (!maxlen)
1398 return gpg_error (GPG_ERR_TRUNCATED); /* Line has been truncated. */
1399 if (!len)
1400 return gpg_error (GPG_ERR_EOF);
1401 if ( (hd->flags & HTTP_FLAG_LOG_RESP) )
1402 log_info ("RESP: `%.*s'\n",
1403 (int)strlen(line)-(*line&&line[1]?2:0),line);
1405 while (!*line);
1407 if ((p = strchr (line, '/')))
1408 *p++ = 0;
1409 if (!p || strcmp (line, "HTTP"))
1410 return 0; /* Assume http 0.9. */
1412 if ((p2 = strpbrk (p, " \t")))
1414 *p2++ = 0;
1415 p2 += strspn (p2, " \t");
1417 if (!p2)
1418 return 0; /* Also assume http 0.9. */
1419 p = p2;
1420 /* TODO: Add HTTP version number check. */
1421 if ((p2 = strpbrk (p, " \t")))
1422 *p2++ = 0;
1423 if (!isdigit ((unsigned int)p[0]) || !isdigit ((unsigned int)p[1])
1424 || !isdigit ((unsigned int)p[2]) || p[3])
1426 /* Malformed HTTP status code - assume http 0.9. */
1427 hd->is_http_0_9 = 1;
1428 hd->status_code = 200;
1429 return 0;
1431 hd->status_code = atoi (p);
1433 /* Skip all the header lines and wait for the empty line. */
1436 maxlen = MAX_LINELEN;
1437 len = my_read_line (hd->fp_read, &hd->buffer, &hd->buffer_size, &maxlen);
1438 line = hd->buffer;
1439 if (!line)
1440 return gpg_error_from_syserror (); /* Out of core. */
1441 /* Note, that we can silently ignore truncated lines. */
1442 if (!len)
1443 return gpg_error (GPG_ERR_EOF);
1444 /* Trim line endings of empty lines. */
1445 if ((*line == '\r' && line[1] == '\n') || *line == '\n')
1446 *line = 0;
1447 if ( (hd->flags & HTTP_FLAG_LOG_RESP) )
1448 log_info ("RESP: `%.*s'\n",
1449 (int)strlen(line)-(*line&&line[1]?2:0),line);
1450 if ( (hd->flags & HTTP_FLAG_NEED_HEADER) && *line )
1452 gpg_error_t err = store_header (hd, line);
1453 if (err)
1454 return err;
1457 while (len && *line);
1459 return 0;
1462 #if 0
1463 static int
1464 start_server ()
1466 struct sockaddr_in mya;
1467 struct sockaddr_in peer;
1468 int fd, client;
1469 fd_set rfds;
1470 int addrlen;
1471 int i;
1473 if ((fd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
1475 log_error ("socket() failed: %s\n", strerror (errno));
1476 return -1;
1478 i = 1;
1479 if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (byte *) & i, sizeof (i)))
1480 log_info ("setsockopt(SO_REUSEADDR) failed: %s\n", strerror (errno));
1482 mya.sin_family = AF_INET;
1483 memset (&mya.sin_addr, 0, sizeof (mya.sin_addr));
1484 mya.sin_port = htons (11371);
1486 if (bind (fd, (struct sockaddr *) &mya, sizeof (mya)))
1488 log_error ("bind to port 11371 failed: %s\n", strerror (errno));
1489 sock_close (fd);
1490 return -1;
1493 if (listen (fd, 5))
1495 log_error ("listen failed: %s\n", strerror (errno));
1496 sock_close (fd);
1497 return -1;
1500 for (;;)
1502 FD_ZERO (&rfds);
1503 FD_SET (fd, &rfds);
1505 if (select (fd + 1, &rfds, NULL, NULL, NULL) <= 0)
1506 continue; /* ignore any errors */
1508 if (!FD_ISSET (fd, &rfds))
1509 continue;
1511 addrlen = sizeof peer;
1512 client = accept (fd, (struct sockaddr *) &peer, &addrlen);
1513 if (client == -1)
1514 continue; /* oops */
1516 log_info ("connect from %s\n", inet_ntoa (peer.sin_addr));
1518 fflush (stdout);
1519 fflush (stderr);
1520 if (!fork ())
1522 int c;
1523 FILE *fp;
1525 fp = fdopen (client, "r");
1526 while ((c = getc (fp)) != EOF)
1527 putchar (c);
1528 fclose (fp);
1529 exit (0);
1531 sock_close (client);
1535 return 0;
1537 #endif
1539 /* Actually connect to a server. Returns the file descriptor or -1 on
1540 error. ERRNO is set on error. */
1541 static int
1542 connect_server (const char *server, unsigned short port,
1543 unsigned int flags, const char *srvtag)
1545 int sock = -1;
1546 int srvcount = 0;
1547 int hostfound = 0;
1548 int srv, connected;
1549 int last_errno = 0;
1550 struct srventry *serverlist = NULL;
1552 /* Not currently using the flags */
1553 (void)flags;
1555 #ifdef HAVE_W32_SYSTEM
1556 unsigned long inaddr;
1558 #ifndef HTTP_NO_WSASTARTUP
1559 init_sockets ();
1560 #endif
1561 /* Win32 gethostbyname doesn't handle IP addresses internally, so we
1562 try inet_addr first on that platform only. */
1563 inaddr = inet_addr(server);
1564 if ( inaddr != INADDR_NONE )
1566 struct sockaddr_in addr;
1568 memset(&addr,0,sizeof(addr));
1570 sock = socket(AF_INET,SOCK_STREAM,0);
1571 if ( sock==INVALID_SOCKET )
1573 log_error("error creating socket: ec=%d\n",(int)WSAGetLastError());
1574 return -1;
1577 addr.sin_family = AF_INET;
1578 addr.sin_port = htons(port);
1579 memcpy (&addr.sin_addr,&inaddr,sizeof(inaddr));
1581 if (!connect (sock,(struct sockaddr *)&addr,sizeof(addr)) )
1582 return sock;
1583 sock_close(sock);
1584 return -1;
1586 #endif /*HAVE_W32_SYSTEM*/
1588 #ifdef USE_DNS_SRV
1589 /* Do the SRV thing */
1590 if (srvtag)
1592 /* We're using SRV, so append the tags. */
1593 if (1+strlen (srvtag) + 6 + strlen (server) + 1 <= MAXDNAME)
1595 char srvname[MAXDNAME];
1597 stpcpy (stpcpy (stpcpy (stpcpy (srvname,"_"), srvtag),
1598 "._tcp."), server);
1599 srvcount = getsrv (srvname, &serverlist);
1602 #endif /*USE_DNS_SRV*/
1604 if (!serverlist)
1606 /* Either we're not using SRV, or the SRV lookup failed. Make
1607 up a fake SRV record. */
1608 serverlist = xtrycalloc (1, sizeof *serverlist);
1609 if (!serverlist)
1610 return -1; /* Out of core. */
1611 serverlist->port = port;
1612 strncpy (serverlist->target, server, MAXDNAME);
1613 serverlist->target[MAXDNAME-1] = '\0';
1614 srvcount = 1;
1617 #ifdef HAVE_GETADDRINFO
1618 connected = 0;
1619 for (srv=0; srv < srvcount && !connected; srv++)
1621 struct addrinfo hints, *res, *ai;
1622 char portstr[35];
1624 sprintf (portstr, "%hu", port);
1625 memset (&hints, 0, sizeof (hints));
1626 hints.ai_socktype = SOCK_STREAM;
1627 if (getaddrinfo (serverlist[srv].target, portstr, &hints, &res))
1628 continue; /* Not found - try next one. */
1629 hostfound = 1;
1631 for (ai = res; ai && !connected; ai = ai->ai_next)
1633 if (sock != -1)
1634 sock_close (sock);
1635 sock = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol);
1636 if (sock == -1)
1638 int save_errno = errno;
1639 log_error ("error creating socket: %s\n", strerror (errno));
1640 freeaddrinfo (res);
1641 xfree (serverlist);
1642 errno = save_errno;
1643 return -1;
1646 if (connect (sock, ai->ai_addr, ai->ai_addrlen))
1647 last_errno = errno;
1648 else
1649 connected = 1;
1651 freeaddrinfo (res);
1653 #else /* !HAVE_GETADDRINFO */
1654 connected = 0;
1655 for (srv=0; srv < srvcount && !connected; srv++)
1657 int i;
1658 struct hostent *host = NULL;
1659 struct sockaddr_in addr;
1661 /* Note: This code is not thread-safe. */
1663 memset (&addr, 0, sizeof (addr));
1664 host = gethostbyname (serverlist[srv].target);
1665 if (!host)
1666 continue;
1667 hostfound = 1;
1669 if (sock != -1)
1670 sock_close (sock);
1671 sock = socket (host->h_addrtype, SOCK_STREAM, 0);
1672 if (sock == -1)
1674 log_error (_("error creating socket: %s\n"), strerror (errno));
1675 xfree (serverlist);
1676 return -1;
1679 addr.sin_family = host->h_addrtype;
1680 if (addr.sin_family != AF_INET)
1682 log_error ("unknown address family for `%s'\n",
1683 serverlist[srv].target);
1684 xfree (serverlist);
1685 return -1;
1687 addr.sin_port = htons (serverlist[srv].port);
1688 if (host->h_length != 4)
1690 log_error ("illegal address length for `%s'\n",
1691 serverlist[srv].target);
1692 xfree (serverlist);
1693 return -1;
1696 /* Try all A records until one responds. */
1697 for (i = 0; host->h_addr_list[i] && !connected; i++)
1699 memcpy (&addr.sin_addr, host->h_addr_list[i], host->h_length);
1700 if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)))
1701 last_errno = errno;
1702 else
1704 connected = 1;
1705 break;
1709 #endif /* !HAVE_GETADDRINFO */
1711 xfree (serverlist);
1713 if (!connected)
1715 #ifdef HAVE_W32_SYSTEM
1716 log_error ("can't connect to `%s': %s%sec=%d\n",
1717 server,
1718 hostfound? "":_("host not found"),
1719 hostfound? "":" - ", (int)WSAGetLastError());
1720 #else
1721 log_error ("can't connect to `%s': %s\n",
1722 server,
1723 hostfound? strerror (last_errno):"host not found");
1724 #endif
1725 if (sock != -1)
1726 sock_close (sock);
1727 errno = last_errno;
1728 return -1;
1730 return sock;
1734 static gpg_error_t
1735 write_server (int sock, const char *data, size_t length)
1737 int nleft;
1739 nleft = length;
1740 while (nleft > 0)
1742 #ifdef HAVE_W32_SYSTEM
1743 int nwritten;
1745 nwritten = send (sock, data, nleft, 0);
1746 if ( nwritten == SOCKET_ERROR )
1748 log_info ("network write failed: ec=%d\n", (int)WSAGetLastError ());
1749 return gpg_error (GPG_ERR_NETWORK);
1751 #else /*!HAVE_W32_SYSTEM*/
1752 int nwritten = write (sock, data, nleft);
1753 if (nwritten == -1)
1755 if (errno == EINTR)
1756 continue;
1757 if (errno == EAGAIN)
1759 struct timeval tv;
1761 tv.tv_sec = 0;
1762 tv.tv_usec = 50000;
1763 select (0, NULL, NULL, NULL, &tv);
1764 continue;
1766 log_info ("network write failed: %s\n", strerror (errno));
1767 return gpg_error_from_syserror ();
1769 #endif /*!HAVE_W32_SYSTEM*/
1770 nleft -= nwritten;
1771 data += nwritten;
1774 return 0;
1779 #ifdef HTTP_USE_ESTREAM
1780 /* Read handler for estream. */
1781 static ssize_t
1782 cookie_read (void *cookie, void *buffer, size_t size)
1784 cookie_t c = cookie;
1785 int nread;
1787 #ifdef HTTP_USE_GNUTLS
1788 if (c->tls_session)
1790 again:
1791 nread = gnutls_record_recv (c->tls_session, buffer, size);
1792 if (nread < 0)
1794 if (nread == GNUTLS_E_INTERRUPTED)
1795 goto again;
1796 if (nread == GNUTLS_E_AGAIN)
1798 struct timeval tv;
1800 tv.tv_sec = 0;
1801 tv.tv_usec = 50000;
1802 select (0, NULL, NULL, NULL, &tv);
1803 goto again;
1805 if (nread == GNUTLS_E_REHANDSHAKE)
1806 goto again; /* A client is allowed to just ignore this request. */
1807 log_info ("TLS network read failed: %s\n", gnutls_strerror (nread));
1808 errno = EIO;
1809 return -1;
1812 else
1813 #endif /*HTTP_USE_GNUTLS*/
1817 #ifdef HAVE_W32_SYSTEM
1818 /* Under Windows we need to use recv for a socket. */
1819 nread = recv (c->fd, buffer, size, 0);
1820 #else
1821 nread = read (c->fd, buffer, size);
1822 #endif
1824 while (nread == -1 && errno == EINTR);
1827 return nread;
1830 /* Write handler for estream. */
1831 static ssize_t
1832 cookie_write (void *cookie, const void *buffer, size_t size)
1834 cookie_t c = cookie;
1835 int nwritten = 0;
1837 #ifdef HTTP_USE_GNUTLS
1838 if (c->tls_session)
1840 int nleft = size;
1841 while (nleft > 0)
1843 nwritten = gnutls_record_send (c->tls_session, buffer, nleft);
1844 if (nwritten <= 0)
1846 if (nwritten == GNUTLS_E_INTERRUPTED)
1847 continue;
1848 if (nwritten == GNUTLS_E_AGAIN)
1850 struct timeval tv;
1852 tv.tv_sec = 0;
1853 tv.tv_usec = 50000;
1854 select (0, NULL, NULL, NULL, &tv);
1855 continue;
1857 log_info ("TLS network write failed: %s\n",
1858 gnutls_strerror (nwritten));
1859 errno = EIO;
1860 return -1;
1862 nleft -= nwritten;
1863 buffer += nwritten;
1866 else
1867 #endif /*HTTP_USE_GNUTLS*/
1869 if ( write_server (c->fd, buffer, size) )
1871 errno = EIO;
1872 nwritten = -1;
1874 else
1875 nwritten = size;
1878 return nwritten;
1881 /* Close handler for estream. */
1882 static int
1883 cookie_close (void *cookie)
1885 cookie_t c = cookie;
1887 if (!c)
1888 return 0;
1890 #ifdef HTTP_USE_GNUTLS
1891 if (c->tls_session && !c->keep_socket)
1893 gnutls_bye (c->tls_session, GNUTLS_SHUT_RDWR);
1895 #endif /*HTTP_USE_GNUTLS*/
1896 if (c->fd != -1 && !c->keep_socket)
1897 sock_close (c->fd);
1899 xfree (c);
1900 return 0;
1902 #endif /*HTTP_USE_ESTREAM*/
1907 /**** Test code ****/
1908 #ifdef TEST
1910 static gpg_error_t
1911 verify_callback (http_t hd, void *tls_context, int reserved)
1913 log_info ("verification of certificates skipped\n");
1914 return 0;
1919 /* static void */
1920 /* my_gnutls_log (int level, const char *text) */
1921 /* { */
1922 /* fprintf (stderr, "gnutls:L%d: %s", level, text); */
1923 /* } */
1926 main (int argc, char **argv)
1928 int rc;
1929 parsed_uri_t uri;
1930 uri_tuple_t r;
1931 http_t hd;
1932 int c;
1933 gnutls_session_t tls_session = NULL;
1934 #ifdef HTTP_USE_GNUTLS
1935 gnutls_certificate_credentials certcred;
1936 const int certprio[] = { GNUTLS_CRT_X509, 0 };
1937 #endif /*HTTP_USE_GNUTLS*/
1938 header_t hdr;
1940 #ifdef HTTP_USE_ESTREAM
1941 es_init ();
1942 #endif
1943 log_set_prefix ("http-test", 1 | 4);
1944 if (argc == 1)
1946 /*start_server (); */
1947 return 0;
1950 if (argc != 2)
1952 fprintf (stderr, "usage: http-test uri\n");
1953 return 1;
1955 argc--;
1956 argv++;
1958 #ifdef HTTP_USE_GNUTLS
1959 rc = gnutls_global_init ();
1960 if (rc)
1961 log_error ("gnutls_global_init failed: %s\n", gnutls_strerror (rc));
1962 rc = gnutls_certificate_allocate_credentials (&certcred);
1963 if (rc)
1964 log_error ("gnutls_certificate_allocate_credentials failed: %s\n",
1965 gnutls_strerror (rc));
1966 /* rc = gnutls_certificate_set_x509_trust_file */
1967 /* (certcred, "ca.pem", GNUTLS_X509_FMT_PEM); */
1968 /* if (rc) */
1969 /* log_error ("gnutls_certificate_set_x509_trust_file failed: %s\n", */
1970 /* gnutls_strerror (rc)); */
1971 rc = gnutls_init (&tls_session, GNUTLS_CLIENT);
1972 if (rc)
1973 log_error ("gnutls_init failed: %s\n", gnutls_strerror (rc));
1974 rc = gnutls_set_default_priority (tls_session);
1975 if (rc)
1976 log_error ("gnutls_set_default_priority failed: %s\n",
1977 gnutls_strerror (rc));
1978 rc = gnutls_certificate_type_set_priority (tls_session, certprio);
1979 if (rc)
1980 log_error ("gnutls_certificate_type_set_priority failed: %s\n",
1981 gnutls_strerror (rc));
1982 rc = gnutls_credentials_set (tls_session, GNUTLS_CRD_CERTIFICATE, certcred);
1983 if (rc)
1984 log_error ("gnutls_credentials_set failed: %s\n", gnutls_strerror (rc));
1985 /* gnutls_global_set_log_function (my_gnutls_log); */
1986 /* gnutls_global_set_log_level (4); */
1988 http_register_tls_callback (verify_callback);
1989 #endif /*HTTP_USE_GNUTLS*/
1991 rc = http_parse_uri (&uri, *argv);
1992 if (rc)
1994 log_error ("`%s': %s\n", *argv, gpg_strerror (rc));
1995 http_release_parsed_uri (uri);
1996 return 1;
1999 printf ("Scheme: %s\n", uri->scheme);
2000 printf ("Host : %s\n", uri->host);
2001 printf ("Port : %u\n", uri->port);
2002 printf ("Path : %s\n", uri->path);
2003 for (r = uri->params; r; r = r->next)
2005 printf ("Params: %s", r->name);
2006 if (!r->no_value)
2008 printf ("=%s", r->value);
2009 if (strlen (r->value) != r->valuelen)
2010 printf (" [real length=%d]", (int) r->valuelen);
2012 putchar ('\n');
2014 for (r = uri->query; r; r = r->next)
2016 printf ("Query : %s", r->name);
2017 if (!r->no_value)
2019 printf ("=%s", r->value);
2020 if (strlen (r->value) != r->valuelen)
2021 printf (" [real length=%d]", (int) r->valuelen);
2023 putchar ('\n');
2025 http_release_parsed_uri (uri);
2026 uri = NULL;
2028 rc = http_open_document (&hd, *argv, NULL,
2029 HTTP_FLAG_NO_SHUTDOWN | HTTP_FLAG_NEED_HEADER,
2030 NULL, tls_session);
2031 if (rc)
2033 log_error ("can't get `%s': %s\n", *argv, gpg_strerror (rc));
2034 return 1;
2036 log_info ("open_http_document succeeded; status=%u\n",
2037 http_get_status_code (hd));
2038 for (hdr = hd->headers; hdr; hdr = hdr->next)
2039 printf ("HDR: %s: %s\n", hdr->name, hdr->value);
2040 switch (http_get_status_code (hd))
2042 case 200:
2043 while ((c = P_ES(getc) (http_get_read_ptr (hd))) != EOF)
2044 putchar (c);
2045 break;
2046 case 301:
2047 case 302:
2048 printf ("Redirected to `%s'\n", http_get_header (hd, "Location"));
2049 break;
2051 http_close (hd, 0);
2053 #ifdef HTTP_USE_GNUTLS
2054 gnutls_deinit (tls_session);
2055 gnutls_certificate_free_credentials (certcred);
2056 gnutls_global_deinit ();
2057 #endif /*HTTP_USE_GNUTLS*/
2059 return 0;
2061 #endif /*TEST*/
2065 Local Variables:
2066 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"
2067 End: