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:
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
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.
48 #ifdef HAVE_W32_SYSTEM
50 #else /*!HAVE_W32_SYSTEM*/
51 # include <sys/types.h>
52 # include <sys/socket.h>
53 # include <sys/time.h>
55 # include <netinet/in.h>
56 # include <arpa/inet.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
66 typedef gnutls_session gnutls_session_t
;
67 typedef gnutls_transport_ptr gnutls_transport_ptr_t
;
68 #endif /*HTTP_USE_GNUTLS*/
79 #else /*!USE_DNS_SRV*/
80 /* If we are not compiling with SRV record support we provide stub
87 unsigned short priority
;
88 unsigned short weight
;
91 char target
[MAXDNAME
];
93 #endif/*!USE_DNS_SRV*/
96 #ifdef HAVE_W32_SYSTEM
97 #define sock_close(a) closesocket(a)
99 #define sock_close(a) close(a)
103 #define EAGAIN EWOULDBLOCK
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" \
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
119 #ifndef HTTP_USE_GNUTLS
120 typedef void * gnutls_session_t
;
122 #if defined(HTTP_USE_GNUTLS) && !defined(HTTP_USE_ESTREAM)
123 #error Use of GNUTLS also requires support for Estream
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
,
132 const char *proxy
, const char *srvtag
);
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
=
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. */
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
;
184 #ifdef HTTP_USE_ESTREAM
188 #else /*!HTTP_USE_ESTREAM*/
191 #endif /*!HTTP_USE_ESTREAM*/
196 char *buffer
; /* Line buffer. */
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
211 #define REQ_WINSOCK_MAJOR 2
212 #define REQ_WINSOCK_MINOR 2
217 deinit_sockets (void)
225 static int initialized
;
226 static WSADATA wsdata
;
231 if ( WSAStartup( MAKEWORD (REQ_WINSOCK_MINOR
, REQ_WINSOCK_MAJOR
), &wsdata
) )
233 log_error ("error initializing socket library: ec=%d\n",
234 (int)WSAGetLastError () );
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
);
246 atexit ( deinit_sockets
);
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.
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"
267 const unsigned int *s
= data
;
270 buffer
= xtrymalloc (strlen (prefix
) + (len
+2)/3*4 + strlen (suffix
) + 1);
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];
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)];
290 *p
++ = bintoasc
[(s
[0] >> 2) & 077];
291 *p
++ = bintoasc
[(s
[0] <<4)&060];
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
;
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
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
)
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
);
333 return gpg_error_from_syserror ();
335 hd
->req_type
= reqtype
;
337 hd
->tls_context
= tls_context
;
339 err
= http_parse_uri (&hd
->uri
, url
);
341 err
= send_request (hd
, auth
, proxy
, srvtag
);
345 if (!hd
->fp_read
&& !hd
->fp_write
&& hd
->sock
!= -1)
346 sock_close (hd
->sock
);
348 P_ES(fclose
) (hd
->fp_read
);
350 P_ES(fclose
) (hd
->fp_write
);
351 http_release_parsed_uri (hd
->uri
);
361 http_start_data (http_t hd
)
365 #ifdef HTTP_USE_ESTREAM
366 es_fputs ("\r\n", hd
->fp_write
);
367 es_fflush (hd
->fp_write
);
369 fflush (hd
->fp_write
);
370 write_server (hd
->sock
, "\r\n", 2);
375 P_ES(fflush
) (hd
->fp_write
);
380 http_wait_response (http_t hd
)
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;
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
;
409 hd
->sock
= dup (hd
->sock
);
412 return gpg_error_from_syserror ();
414 P_ES(fclose
) (hd
->fp_write
);
416 #ifdef HTTP_USE_ESTREAM
417 hd
->write_cookie
= NULL
;
420 if (!(hd
->flags
& HTTP_FLAG_NO_SHUTDOWN
))
421 shutdown (hd
->sock
, 1);
424 #ifdef HTTP_USE_ESTREAM
428 cookie
= xtrycalloc (1, sizeof *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
);
439 return gpg_error_from_syserror ();
442 #else /*!HTTP_USE_ESTREAM*/
443 hd
->fp_read
= fdopen (hd
->sock
, "r");
445 return gpg_error_from_syserror ();
446 #endif /*!HTTP_USE_ESTREAM*/
448 err
= parse_response (hd
);
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
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
)
464 err
= http_open (r_hd
, HTTP_REQ_GET
, document
, auth
, flags
,
465 proxy
, tls_context
, srvtag
);
469 err
= http_wait_response (*r_hd
);
471 http_close (*r_hd
, 0);
478 http_close (http_t hd
, int keep_read_stream
)
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
);
487 P_ES(fclose
) (hd
->fp_write
);
488 http_release_parsed_uri (hd
->uri
);
491 header_t tmp
= hd
->headers
->next
;
492 xfree (hd
->headers
->value
);
501 #ifdef HTTP_USE_ESTREAM
503 http_get_read_ptr (http_t hd
)
505 return hd
?hd
->fp_read
:NULL
;
508 http_get_write_ptr (http_t hd
)
510 return hd
?hd
->fp_write
:NULL
;
512 #else /*!HTTP_USE_ESTREAM*/
514 http_get_read_ptr (http_t hd
)
516 return hd
?hd
->fp_read
:NULL
;
519 http_get_write_ptr (http_t hd
)
521 return hd
?hd
->fp_write
:NULL
;
523 #endif /*!HTTP_USE_ESTREAM*/
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).
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);
546 http_release_parsed_uri (parsed_uri_t uri
)
552 for (r
= uri
->query
; r
; r
= r2
)
563 do_parse_uri (parsed_uri_t uri
, int only_local_part
)
566 char *p
, *p2
, *p3
, *pp
;
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
;
575 uri
->params
= uri
->query
= NULL
;
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. */
588 for (pp
=p
; *pp
; pp
++)
589 *pp
= tolower (*(unsigned char*)pp
);
591 if (!strcmp (uri
->scheme
, "http"))
593 #ifdef HTTP_USE_GNUTLS
594 else if (!strcmp (uri
->scheme
, "https"))
601 return gpg_error (GPG_ERR_INV_URI
); /* Unsupported scheme */
605 /* Find the hostname */
607 return gpg_error (GPG_ERR_INV_URI
); /* Does not start with a slash. */
610 if (*p
== '/') /* There seems to be a hostname. */
613 if ((p2
= strchr (p
, '/')))
616 /* Check for username/password encoding */
617 if ((p3
= strchr (p
, '@')))
624 for (pp
=p
; *pp
; pp
++)
625 *pp
= tolower (*(unsigned char*)pp
);
627 /* Handle an IPv6 literal */
628 if( *p
== '[' && (p3
=strchr( p
, ']' )) )
631 /* worst case, uri->host should have length 0, points to \0 */
638 if ((p3
= strchr (p
, ':')))
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. */
650 } /* End global URI part. */
652 /* Parse the pathname part */
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
, '?')))
663 if ((n
= remove_escapes (p
)) < 0)
664 return gpg_error (GPG_ERR_BAD_URI
);
666 return gpg_error (GPG_ERR_BAD_URI
); /* Path includes a Nul. */
670 return 0; /* We don't have a query string. Okay. */
672 /* Now parse the query string. */
678 if ((p2
= strchr (p
, '&')))
680 if (!(elem
= parse_tuple (p
)))
681 return gpg_error (GPG_ERR_BAD_URI
);
695 * Remove all %xx escapes; this is done in-place. Returns: New length
699 remove_escapes (char *string
)
702 unsigned char *p
, *s
;
704 for (p
= s
= (unsigned char*)string
; *s
; s
++)
708 if (s
[1] && s
[2] && isxdigit (s
[1]) && isxdigit (s
[2]))
711 *p
= *s
>= '0' && *s
<= '9' ? *s
- '0' :
712 *s
>= 'A' && *s
<= 'F' ? *s
- 'A' + 10 : *s
- 'a' + 10;
715 *p
|= *s
>= '0' && *s
<= '9' ? *s
- '0' :
716 *s
>= 'A' && *s
<= 'F' ? *s
- 'A' + 10 : *s
- 'a' + 10;
729 return -1; /* Bad URI. */
738 *p
= 0; /* Make sure to keep a string terminator. */
744 insert_escapes (char *buffer
, const char *string
,
747 const unsigned char *s
= (const unsigned char*)string
;
752 if (strchr (VALID_URI_CHARS
, *s
) && !strchr (special
, *s
))
755 *(unsigned char*)buffer
++ = *s
;
762 sprintf (buffer
, "%%%02X", *s
);
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. */
778 http_escape_string (const char *string
, const char *specials
)
783 n
= insert_escapes (NULL
, string
, specials
);
784 buf
= xtrymalloc (n
+1);
787 insert_escapes (buf
, string
, specials
);
796 parse_tuple (char *string
)
803 if ((p2
= strchr (p
, '=')))
805 if ((n
= remove_escapes (p
)) < 0)
806 return NULL
; /* Bad URI. */
808 return NULL
; /* Name with a Nul in it. */
809 tuple
= xtrycalloc (1, sizeof *tuple
);
811 return NULL
; /* Out of core. */
813 if (!p2
) /* We have only the name, so we assume an empty value string. */
815 tuple
->value
= p
+ strlen (p
);
817 tuple
->no_value
= 1; /* Explicitly mark that we have seen no '='. */
819 else /* Name and value. */
821 if ((n
= remove_escapes (p2
)) < 0)
824 return NULL
; /* Bad URI. */
834 * Send a HTTP request to the server
835 * Returns 0 if the request was successful
838 send_request (http_t hd
, const char *auth
, const char *proxy
,const char *srvtag
)
840 gnutls_session_t tls_session
;
845 const char *http_proxy
= NULL
;
846 char *proxy_authstr
= NULL
;
847 char *authstr
= NULL
;
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
))
870 err
= http_parse_uri (&uri
, http_proxy
);
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
);
882 remove_escapes (uri
->auth
);
883 proxy_authstr
= make_header_line ("Proxy-Authorization: Basic ",
885 uri
->auth
, strlen(uri
->auth
));
888 err
= gpg_error_from_syserror ();
889 http_release_parsed_uri (uri
);
894 hd
->sock
= connect_server (*uri
->host
? uri
->host
: "localhost",
895 uri
->port
? uri
->port
: 80,
898 http_release_parsed_uri (uri
);
902 hd
->sock
= connect_server (server
, port
, hd
->flags
, srvtag
);
908 xfree (proxy_authstr
);
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
)
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
);
927 log_info ("TLS handshake failed: %s\n", gnutls_strerror (rc
));
928 xfree (proxy_authstr
);
929 return gpg_error (GPG_ERR_NETWORK
);
934 err
= tls_callback (hd
, tls_session
, 0);
937 log_info ("TLS connection authentication failed: %s\n",
939 xfree (proxy_authstr
);
944 #endif /*HTTP_USE_GNUTLS*/
946 if (auth
|| hd
->uri
->auth
)
952 myauth
= xtrystrdup (auth
);
955 xfree (proxy_authstr
);
956 return gpg_error_from_syserror ();
958 remove_escapes (myauth
);
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
));
973 xfree (proxy_authstr
);
974 return gpg_error_from_syserror ();
978 p
= build_rel_path (hd
->uri
);
980 return gpg_error_from_syserror ();
982 request
= xtrymalloc (2 * strlen (server
)
984 + (authstr
?strlen(authstr
):0)
985 + (proxy_authstr
?strlen(proxy_authstr
):0)
989 err
= gpg_error_from_syserror ();
992 xfree (proxy_authstr
);
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
: "");
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
:"");
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. */
1031 cookie
= xtrycalloc (1, sizeof *cookie
);
1034 err
= gpg_error_from_syserror ();
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
);
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 ();
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
));
1065 hd
->fp_write
= fdopen (hd
->sock
, "w");
1067 err
= gpg_error_from_syserror ();
1069 #endif /*!HTTP_USE_ESTREAM*/
1073 xfree (proxy_authstr
);
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.
1085 build_rel_path (parsed_uri_t uri
)
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
)
1097 n
+= insert_escapes (NULL
, r
->name
, "%;?&=");
1101 n
+= insert_escapes (NULL
, r
->value
, "%;?&=");
1106 /* Now allocate and copy. */
1107 p
= rel_path
= xtrymalloc (n
);
1110 n
= insert_escapes (p
, uri
->path
, "%;?&");
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
, "%;?&=");
1121 /* TODO: Use valuelen. */
1122 n
= insert_escapes (p
, r
->value
, "%;?&=");
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
1151 #ifdef HTTP_USE_ESTREAM
1156 char **addr_of_buffer
,
1157 size_t *length_of_buffer
, size_t *max_length
)
1160 char *buffer
= *addr_of_buffer
;
1161 size_t length
= *length_of_buffer
;
1163 size_t maxlen
= *max_length
;
1166 if (!buffer
) /* Must allocate a new buffer. */
1169 buffer
= xtrymalloc (length
);
1170 *addr_of_buffer
= buffer
;
1173 *length_of_buffer
= *max_length
= 0;
1176 *length_of_buffer
= length
;
1179 length
-= 3; /* Reserve 3 bytes (cr,lf,eol). */
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). */
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
;
1202 *length_of_buffer
= *max_length
= 0;
1206 buffer
= *addr_of_buffer
;
1207 *length_of_buffer
= length
;
1208 length
-= 3; /* And re-adjust for the reservation. */
1209 p
= buffer
+ nbytes
;
1216 *p
= 0; /* Make sure the line is a string. */
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. */
1226 capitalize_header_name (char *name
)
1230 for (; *name
&& *name
!= ':'; name
++)
1236 if (*name
>= 'a' && *name
<= 'z')
1237 *name
= *name
- 'a' + 'A';
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. */
1250 store_header (http_t hd
, char *line
)
1257 if (n
&& line
[n
-1] == '\n')
1260 if (n
&& line
[n
-1] == '\r')
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. */
1270 return gpg_error (GPG_ERR_PROTOCOL_VIOLATION
);
1271 n
+= strlen (hd
->headers
->value
);
1272 p
= xtrymalloc (n
+1);
1274 return gpg_error_from_syserror ();
1275 strcpy (stpcpy (p
, hd
->headers
->value
), line
);
1276 xfree (hd
->headers
->value
);
1277 hd
->headers
->value
= p
;
1281 capitalize_header_name (line
);
1282 p
= strchr (line
, ':');
1284 return gpg_error (GPG_ERR_PROTOCOL_VIOLATION
);
1286 while (*p
== ' ' || *p
== '\t')
1290 for (h
=hd
->headers
; h
; h
= h
->next
)
1291 if ( !strcmp (h
->name
, line
) )
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);
1299 return gpg_error_from_syserror ();
1300 strcpy (stpcpy (stpcpy (p
, h
->value
), ","), value
);
1306 /* Append a new header. */
1307 h
= xtrymalloc (sizeof *h
+ strlen (line
));
1309 return gpg_error_from_syserror ();
1310 strcpy (h
->name
, line
);
1311 h
->value
= xtrymalloc (strlen (value
)+1);
1315 return gpg_error_from_syserror ();
1317 strcpy (h
->value
, value
);
1318 h
->next
= hd
->headers
;
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. */
1333 http_get_header (http_t hd
, const char *name
)
1337 for (h
=hd
->headers
; h
; h
= h
->next
)
1338 if ( !strcmp (h
->name
, name
) )
1346 * Parse the response from a server.
1347 * Returns: Errorcode and sets some files in the handle
1350 parse_response (http_t hd
)
1352 char *line
, *p
, *p2
;
1355 /* Delete old header lines. */
1358 header_t tmp
= hd
->headers
->next
;
1359 xfree (hd
->headers
->value
);
1360 xfree (hd
->headers
);
1364 /* Wait for the status line. */
1367 maxlen
= MAX_LINELEN
;
1368 len
= my_read_line (hd
->fp_read
, &hd
->buffer
, &hd
->buffer_size
, &maxlen
);
1371 return gpg_error_from_syserror (); /* Out of core. */
1373 return gpg_error (GPG_ERR_TRUNCATED
); /* Line has been truncated. */
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
);
1382 if ((p
= strchr (line
, '/')))
1384 if (!p
|| strcmp (line
, "HTTP"))
1385 return 0; /* Assume http 0.9. */
1387 if ((p2
= strpbrk (p
, " \t")))
1390 p2
+= strspn (p2
, " \t");
1393 return 0; /* Also assume http 0.9. */
1395 /* TODO: Add HTTP version number check. */
1396 if ((p2
= strpbrk (p
, " \t")))
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;
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
);
1415 return gpg_error_from_syserror (); /* Out of core. */
1416 /* Note, that we can silently ignore truncated lines. */
1418 return gpg_error (GPG_ERR_EOF
);
1419 /* Trim line endings of empty lines. */
1420 if ((*line
== '\r' && line
[1] == '\n') || *line
== '\n')
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
);
1432 while (len
&& *line
);
1441 struct sockaddr_in mya
;
1442 struct sockaddr_in peer
;
1448 if ((fd
= socket (AF_INET
, SOCK_STREAM
, 0)) == -1)
1450 log_error ("socket() failed: %s\n", strerror (errno
));
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
));
1470 log_error ("listen failed: %s\n", strerror (errno
));
1480 if (select (fd
+ 1, &rfds
, NULL
, NULL
, NULL
) <= 0)
1481 continue; /* ignore any errors */
1483 if (!FD_ISSET (fd
, &rfds
))
1486 addrlen
= sizeof peer
;
1487 client
= accept (fd
, (struct sockaddr
*) &peer
, &addrlen
);
1489 continue; /* oops */
1491 log_info ("connect from %s\n", inet_ntoa (peer
.sin_addr
));
1500 fp
= fdopen (client
, "r");
1501 while ((c
= getc (fp
)) != EOF
)
1506 sock_close (client
);
1514 /* Actually connect to a server. Returns the file descriptor or -1 on
1515 error. ERRNO is set on error. */
1517 connect_server (const char *server
, unsigned short port
,
1518 unsigned int flags
, const char *srvtag
)
1525 struct srventry
*serverlist
= NULL
;
1527 /* Not currently using the flags */
1530 #ifdef HAVE_W32_SYSTEM
1531 unsigned long inaddr
;
1533 #ifndef HTTP_NO_WSASTARTUP
1536 /* Win32 gethostbyname doesn't handle IP addresses internally, so we
1537 try inet_addr first on that platform only. */
1538 inaddr
= inet_addr(server
);
1539 if ( inaddr
!= INADDR_NONE
)
1541 struct sockaddr_in addr
;
1543 memset(&addr
,0,sizeof(addr
));
1545 sock
= socket(AF_INET
,SOCK_STREAM
,0);
1546 if ( sock
==INVALID_SOCKET
)
1548 log_error("error creating socket: ec=%d\n",(int)WSAGetLastError());
1552 addr
.sin_family
= AF_INET
;
1553 addr
.sin_port
= htons(port
);
1554 memcpy (&addr
.sin_addr
,&inaddr
,sizeof(inaddr
));
1556 if (!connect (sock
,(struct sockaddr
*)&addr
,sizeof(addr
)) )
1561 #endif /*HAVE_W32_SYSTEM*/
1564 /* Do the SRV thing */
1567 /* We're using SRV, so append the tags. */
1568 if (1+strlen (srvtag
) + 6 + strlen (server
) + 1 <= MAXDNAME
)
1570 char srvname
[MAXDNAME
];
1572 stpcpy (stpcpy (stpcpy (stpcpy (srvname
,"_"), srvtag
),
1574 srvcount
= getsrv (srvname
, &serverlist
);
1577 #endif /*USE_DNS_SRV*/
1581 /* Either we're not using SRV, or the SRV lookup failed. Make
1582 up a fake SRV record. */
1583 serverlist
= xtrycalloc (1, sizeof *serverlist
);
1585 return -1; /* Out of core. */
1586 serverlist
->port
= port
;
1587 strncpy (serverlist
->target
, server
, MAXDNAME
);
1588 serverlist
->target
[MAXDNAME
-1] = '\0';
1592 #ifdef HAVE_GETADDRINFO
1594 for (srv
=0; srv
< srvcount
&& !connected
; srv
++)
1596 struct addrinfo hints
, *res
, *ai
;
1599 sprintf (portstr
, "%hu", port
);
1600 memset (&hints
, 0, sizeof (hints
));
1601 hints
.ai_socktype
= SOCK_STREAM
;
1602 if (getaddrinfo (serverlist
[srv
].target
, portstr
, &hints
, &res
))
1603 continue; /* Not found - try next one. */
1606 for (ai
= res
; ai
&& !connected
; ai
= ai
->ai_next
)
1610 sock
= socket (ai
->ai_family
, ai
->ai_socktype
, ai
->ai_protocol
);
1613 int save_errno
= errno
;
1614 log_error ("error creating socket: %s\n", strerror (errno
));
1621 if (connect (sock
, ai
->ai_addr
, ai
->ai_addrlen
))
1628 #else /* !HAVE_GETADDRINFO */
1630 for (srv
=0; srv
< srvcount
&& !connected
; srv
++)
1633 struct hostent
*host
= NULL
;
1634 struct sockaddr_in addr
;
1636 /* Note: This code is not thread-safe. */
1638 memset (&addr
, 0, sizeof (addr
));
1639 host
= gethostbyname (serverlist
[srv
].target
);
1646 sock
= socket (host
->h_addrtype
, SOCK_STREAM
, 0);
1649 log_error (_("error creating socket: %s\n"), strerror (errno
));
1654 addr
.sin_family
= host
->h_addrtype
;
1655 if (addr
.sin_family
!= AF_INET
)
1657 log_error ("unknown address family for `%s'\n",
1658 serverlist
[srv
].target
);
1662 addr
.sin_port
= htons (serverlist
[srv
].port
);
1663 if (host
->h_length
!= 4)
1665 log_error ("illegal address length for `%s'\n",
1666 serverlist
[srv
].target
);
1671 /* Try all A records until one responds. */
1672 for (i
= 0; host
->h_addr_list
[i
] && !connected
; i
++)
1674 memcpy (&addr
.sin_addr
, host
->h_addr_list
[i
], host
->h_length
);
1675 if (connect (sock
, (struct sockaddr
*) &addr
, sizeof (addr
)))
1684 #endif /* !HAVE_GETADDRINFO */
1690 #ifdef HAVE_W32_SYSTEM
1691 log_error ("can't connect to `%s': %s%sec=%d\n",
1693 hostfound
? "":_("host not found"),
1694 hostfound
? "":" - ", (int)WSAGetLastError());
1696 log_error ("can't connect to `%s': %s\n",
1698 hostfound
? strerror (last_errno
):"host not found");
1710 write_server (int sock
, const char *data
, size_t length
)
1717 #ifdef HAVE_W32_SYSTEM
1720 nwritten
= send (sock
, data
, nleft
, 0);
1721 if ( nwritten
== SOCKET_ERROR
)
1723 log_info ("network write failed: ec=%d\n", (int)WSAGetLastError ());
1724 return gpg_error (GPG_ERR_NETWORK
);
1726 #else /*!HAVE_W32_SYSTEM*/
1727 int nwritten
= write (sock
, data
, nleft
);
1732 if (errno
== EAGAIN
)
1738 select (0, NULL
, NULL
, NULL
, &tv
);
1741 log_info ("network write failed: %s\n", strerror (errno
));
1742 return gpg_error_from_syserror ();
1744 #endif /*!HAVE_W32_SYSTEM*/
1754 #ifdef HTTP_USE_ESTREAM
1755 /* Read handler for estream. */
1757 cookie_read (void *cookie
, void *buffer
, size_t size
)
1759 cookie_t c
= cookie
;
1762 #ifdef HTTP_USE_GNUTLS
1766 nread
= gnutls_record_recv (c
->tls_session
, buffer
, size
);
1769 if (nread
== GNUTLS_E_INTERRUPTED
)
1771 if (nread
== GNUTLS_E_AGAIN
)
1777 select (0, NULL
, NULL
, NULL
, &tv
);
1780 if (nread
== GNUTLS_E_REHANDSHAKE
)
1781 goto again
; /* A client is allowed to just ignore this request. */
1782 log_info ("TLS network read failed: %s\n", gnutls_strerror (nread
));
1788 #endif /*HTTP_USE_GNUTLS*/
1792 #ifdef HAVE_W32_SYSTEM
1793 /* Under Windows we need to use recv for a socket. */
1794 nread
= recv (c
->fd
, buffer
, size
, 0);
1796 nread
= read (c
->fd
, buffer
, size
);
1799 while (nread
== -1 && errno
== EINTR
);
1805 /* Write handler for estream. */
1807 cookie_write (void *cookie
, const void *buffer
, size_t size
)
1809 cookie_t c
= cookie
;
1812 #ifdef HTTP_USE_GNUTLS
1818 nwritten
= gnutls_record_send (c
->tls_session
, buffer
, nleft
);
1821 if (nwritten
== GNUTLS_E_INTERRUPTED
)
1823 if (nwritten
== GNUTLS_E_AGAIN
)
1829 select (0, NULL
, NULL
, NULL
, &tv
);
1832 log_info ("TLS network write failed: %s\n",
1833 gnutls_strerror (nwritten
));
1842 #endif /*HTTP_USE_GNUTLS*/
1844 if ( write_server (c
->fd
, buffer
, size
) )
1856 /* Close handler for estream. */
1858 cookie_close (void *cookie
)
1860 cookie_t c
= cookie
;
1865 #ifdef HTTP_USE_GNUTLS
1866 if (c
->tls_session
&& !c
->keep_socket
)
1868 gnutls_bye (c
->tls_session
, GNUTLS_SHUT_RDWR
);
1870 #endif /*HTTP_USE_GNUTLS*/
1871 if (c
->fd
!= -1 && !c
->keep_socket
)
1877 #endif /*HTTP_USE_ESTREAM*/
1882 /**** Test code ****/
1886 verify_callback (http_t hd
, void *tls_context
, int reserved
)
1888 log_info ("verification of certificates skipped\n");
1895 /* my_gnutls_log (int level, const char *text) */
1897 /* fprintf (stderr, "gnutls:L%d: %s", level, text); */
1901 main (int argc
, char **argv
)
1908 gnutls_session_t tls_session
= NULL
;
1909 #ifdef HTTP_USE_GNUTLS
1910 gnutls_certificate_credentials certcred
;
1911 const int certprio
[] = { GNUTLS_CRT_X509
, 0 };
1912 #endif /*HTTP_USE_GNUTLS*/
1915 #ifdef HTTP_USE_ESTREAM
1918 log_set_prefix ("http-test", 1 | 4);
1921 /*start_server (); */
1927 fprintf (stderr
, "usage: http-test uri\n");
1933 #ifdef HTTP_USE_GNUTLS
1934 rc
= gnutls_global_init ();
1936 log_error ("gnutls_global_init failed: %s\n", gnutls_strerror (rc
));
1937 rc
= gnutls_certificate_allocate_credentials (&certcred
);
1939 log_error ("gnutls_certificate_allocate_credentials failed: %s\n",
1940 gnutls_strerror (rc
));
1941 /* rc = gnutls_certificate_set_x509_trust_file */
1942 /* (certcred, "ca.pem", GNUTLS_X509_FMT_PEM); */
1944 /* log_error ("gnutls_certificate_set_x509_trust_file failed: %s\n", */
1945 /* gnutls_strerror (rc)); */
1946 rc
= gnutls_init (&tls_session
, GNUTLS_CLIENT
);
1948 log_error ("gnutls_init failed: %s\n", gnutls_strerror (rc
));
1949 rc
= gnutls_set_default_priority (tls_session
);
1951 log_error ("gnutls_set_default_priority failed: %s\n",
1952 gnutls_strerror (rc
));
1953 rc
= gnutls_certificate_type_set_priority (tls_session
, certprio
);
1955 log_error ("gnutls_certificate_type_set_priority failed: %s\n",
1956 gnutls_strerror (rc
));
1957 rc
= gnutls_credentials_set (tls_session
, GNUTLS_CRD_CERTIFICATE
, certcred
);
1959 log_error ("gnutls_credentials_set failed: %s\n", gnutls_strerror (rc
));
1960 /* gnutls_global_set_log_function (my_gnutls_log); */
1961 /* gnutls_global_set_log_level (4); */
1963 http_register_tls_callback (verify_callback
);
1964 #endif /*HTTP_USE_GNUTLS*/
1966 rc
= http_parse_uri (&uri
, *argv
);
1969 log_error ("`%s': %s\n", *argv
, gpg_strerror (rc
));
1970 http_release_parsed_uri (uri
);
1974 printf ("Scheme: %s\n", uri
->scheme
);
1975 printf ("Host : %s\n", uri
->host
);
1976 printf ("Port : %u\n", uri
->port
);
1977 printf ("Path : %s\n", uri
->path
);
1978 for (r
= uri
->params
; r
; r
= r
->next
)
1980 printf ("Params: %s", r
->name
);
1983 printf ("=%s", r
->value
);
1984 if (strlen (r
->value
) != r
->valuelen
)
1985 printf (" [real length=%d]", (int) r
->valuelen
);
1989 for (r
= uri
->query
; r
; r
= r
->next
)
1991 printf ("Query : %s", r
->name
);
1994 printf ("=%s", r
->value
);
1995 if (strlen (r
->value
) != r
->valuelen
)
1996 printf (" [real length=%d]", (int) r
->valuelen
);
2000 http_release_parsed_uri (uri
);
2003 rc
= http_open_document (&hd
, *argv
, NULL
,
2004 HTTP_FLAG_NO_SHUTDOWN
| HTTP_FLAG_NEED_HEADER
,
2008 log_error ("can't get `%s': %s\n", *argv
, gpg_strerror (rc
));
2011 log_info ("open_http_document succeeded; status=%u\n",
2012 http_get_status_code (hd
));
2013 for (hdr
= hd
->headers
; hdr
; hdr
= hdr
->next
)
2014 printf ("HDR: %s: %s\n", hdr
->name
, hdr
->value
);
2015 switch (http_get_status_code (hd
))
2018 while ((c
= P_ES(getc
) (http_get_read_ptr (hd
))) != EOF
)
2023 printf ("Redirected to `%s'\n", http_get_header (hd
, "Location"));
2028 #ifdef HTTP_USE_GNUTLS
2029 gnutls_deinit (tls_session
);
2030 gnutls_certificate_free_credentials (certcred
);
2031 gnutls_global_deinit ();
2032 #endif /*HTTP_USE_GNUTLS*/
2041 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"