1 /* http.c - HTTP protocol handler
2 * Copyright (C) 1999, 2001, 2002, 2003, 2004,
3 * 2006 Free Software Foundation, Inc.
5 * This file is part of GnuPG.
7 * GnuPG is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * GnuPG is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 /* Simple HTTP client implementation. We try to keep the code as
22 self-contained as possible. There are some contraints however:
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
,
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
=
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
,
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
);
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
,
464 err
= http_open (r_hd
, HTTP_REQ_GET
, document
, auth
, flags
,
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 if ((p3
= strchr (p
, ':')))
630 uri
->port
= atoi (p3
);
634 if ((n
= remove_escapes (uri
->host
)) < 0)
635 return gpg_error (GPG_ERR_BAD_URI
);
637 return gpg_error (GPG_ERR_BAD_URI
); /* Hostname incudes a Nul. */
640 } /* End global URI part. */
642 /* Parse the pathname part */
644 return 0; /* We don't have a path. Okay. */
646 /* TODO: Here we have to check params. */
648 /* Do we have a query part? */
649 if ((p2
= strchr (p
, '?')))
653 if ((n
= remove_escapes (p
)) < 0)
654 return gpg_error (GPG_ERR_BAD_URI
);
656 return gpg_error (GPG_ERR_BAD_URI
); /* Path includes a Nul. */
660 return 0; /* We don't have a query string. Okay. */
662 /* Now parse the query string. */
668 if ((p2
= strchr (p
, '&')))
670 if (!(elem
= parse_tuple (p
)))
671 return gpg_error (GPG_ERR_BAD_URI
);
685 * Remove all %xx escapes; this is done in-place. Returns: New length
689 remove_escapes (char *string
)
692 unsigned char *p
, *s
;
694 for (p
= s
= (unsigned char*)string
; *s
; s
++)
698 if (s
[1] && s
[2] && isxdigit (s
[1]) && isxdigit (s
[2]))
701 *p
= *s
>= '0' && *s
<= '9' ? *s
- '0' :
702 *s
>= 'A' && *s
<= 'F' ? *s
- 'A' + 10 : *s
- 'a' + 10;
705 *p
|= *s
>= '0' && *s
<= '9' ? *s
- '0' :
706 *s
>= 'A' && *s
<= 'F' ? *s
- 'A' + 10 : *s
- 'a' + 10;
719 return -1; /* Bad URI. */
728 *p
= 0; /* Make sure to keep a string terminator. */
734 insert_escapes (char *buffer
, const char *string
,
737 const unsigned char *s
= (const unsigned char*)string
;
742 if (strchr (VALID_URI_CHARS
, *s
) && !strchr (special
, *s
))
745 *(unsigned char*)buffer
++ = *s
;
752 sprintf (buffer
, "%%%02X", *s
);
762 /* Allocate a new string from STRING using standard HTTP escaping as
763 well as escaping of characters given in SPECIALS. A common pattern
764 for SPECIALS is "%;?&=". However it depends on the needs, for
765 example "+" and "/: often needs to be escaped too. Returns NULL on
766 failure and sets ERRNO. */
768 http_escape_string (const char *string
, const char *specials
)
773 n
= insert_escapes (NULL
, string
, specials
);
774 buf
= xtrymalloc (n
+1);
777 insert_escapes (buf
, string
, specials
);
786 parse_tuple (char *string
)
793 if ((p2
= strchr (p
, '=')))
795 if ((n
= remove_escapes (p
)) < 0)
796 return NULL
; /* Bad URI. */
798 return NULL
; /* Name with a Nul in it. */
799 tuple
= xtrycalloc (1, sizeof *tuple
);
801 return NULL
; /* Out of core. */
803 if (!p2
) /* We have only the name, so we assume an empty value string. */
805 tuple
->value
= p
+ strlen (p
);
807 tuple
->no_value
= 1; /* Explicitly mark that we have seen no '='. */
809 else /* Name and value. */
811 if ((n
= remove_escapes (p2
)) < 0)
814 return NULL
; /* Bad URI. */
824 * Send a HTTP request to the server
825 * Returns 0 if the request was successful
828 send_request (http_t hd
, const char *auth
, const char *proxy
)
830 gnutls_session_t tls_session
;
835 const char *http_proxy
= NULL
;
836 char *proxy_authstr
= NULL
;
837 char *authstr
= NULL
;
840 tls_session
= hd
->tls_context
;
841 if (hd
->uri
->use_tls
&& !tls_session
)
843 log_error ("TLS requested but no GNUTLS context provided\n");
844 return gpg_error (GPG_ERR_INTERNAL
);
847 server
= *hd
->uri
->host
? hd
->uri
->host
: "localhost";
848 port
= hd
->uri
->port
? hd
->uri
->port
: 80;
850 if ( (proxy
&& *proxy
)
851 || ( (hd
->flags
& HTTP_FLAG_TRY_PROXY
)
852 && (http_proxy
= getenv (HTTP_PROXY_ENV
))
860 err
= http_parse_uri (&uri
, http_proxy
);
863 log_error ("invalid HTTP proxy (%s): %s\n",
864 http_proxy
, gpg_strerror (err
));
865 http_release_parsed_uri (uri
);
866 return gpg_error (GPG_ERR_CONFIGURATION
);
872 remove_escapes (uri
->auth
);
873 proxy_authstr
= make_header_line ("Proxy-Authorization: Basic ",
875 uri
->auth
, strlen(uri
->auth
));
878 err
= gpg_error_from_syserror ();
879 http_release_parsed_uri (uri
);
884 hd
->sock
= connect_server (*uri
->host
? uri
->host
: "localhost",
885 uri
->port
? uri
->port
: 80,
886 hd
->flags
, hd
->uri
->scheme
);
888 http_release_parsed_uri (uri
);
892 hd
->sock
= connect_server (server
, port
, hd
->flags
, hd
->uri
->scheme
);
898 xfree (proxy_authstr
);
900 ? gpg_error_from_errno (save_errno
)
901 : gpg_error (GPG_ERR_NOT_FOUND
));
904 #ifdef HTTP_USE_GNUTLS
905 if (hd
->uri
->use_tls
)
909 gnutls_transport_set_ptr (tls_session
, (gnutls_transport_ptr_t
)hd
->sock
);
912 rc
= gnutls_handshake (tls_session
);
914 while (rc
== GNUTLS_E_INTERRUPTED
|| rc
== GNUTLS_E_AGAIN
);
917 log_info ("TLS handshake failed: %s\n", gnutls_strerror (rc
));
918 xfree (proxy_authstr
);
919 return gpg_error (GPG_ERR_NETWORK
);
924 err
= tls_callback (hd
, tls_session
, 0);
927 log_info ("TLS connection authentication failed: %s\n",
929 xfree (proxy_authstr
);
934 #endif /*HTTP_USE_GNUTLS*/
936 if (auth
|| hd
->uri
->auth
)
942 myauth
= xtrystrdup (auth
);
945 xfree (proxy_authstr
);
946 return gpg_error_from_syserror ();
948 remove_escapes (myauth
);
952 remove_escapes (hd
->uri
->auth
);
953 myauth
= hd
->uri
->auth
;
956 authstr
= make_header_line ("Authorization: Basic %s", "\r\n",
957 myauth
, strlen (myauth
));
963 xfree (proxy_authstr
);
964 return gpg_error_from_syserror ();
968 p
= build_rel_path (hd
->uri
);
970 return gpg_error_from_syserror ();
972 request
= xtrymalloc (2 * strlen (server
)
974 + (authstr
?strlen(authstr
):0)
975 + (proxy_authstr
?strlen(proxy_authstr
):0)
979 err
= gpg_error_from_syserror ();
982 xfree (proxy_authstr
);
986 if (http_proxy
&& *http_proxy
)
988 sprintf (request
, "%s http://%s:%hu%s%s HTTP/1.0\r\n%s%s",
989 hd
->req_type
== HTTP_REQ_GET
? "GET" :
990 hd
->req_type
== HTTP_REQ_HEAD
? "HEAD" :
991 hd
->req_type
== HTTP_REQ_POST
? "POST" : "OOPS",
992 server
, port
, *p
== '/' ? "" : "/", p
,
993 authstr
? authstr
: "",
994 proxy_authstr
? proxy_authstr
: "");
1003 sprintf (portstr
, ":%u", port
);
1005 sprintf (request
, "%s %s%s HTTP/1.0\r\nHost: %s%s\r\n%s",
1006 hd
->req_type
== HTTP_REQ_GET
? "GET" :
1007 hd
->req_type
== HTTP_REQ_HEAD
? "HEAD" :
1008 hd
->req_type
== HTTP_REQ_POST
? "POST" : "OOPS",
1009 *p
== '/' ? "" : "/", p
, server
, portstr
,
1010 authstr
? authstr
:"");
1015 #ifdef HTTP_USE_ESTREAM
1016 /* First setup estream so that we can write even the first line
1017 using estream. This is also required for the sake of gnutls. */
1021 cookie
= xtrycalloc (1, sizeof *cookie
);
1024 err
= gpg_error_from_syserror ();
1027 cookie
->fd
= hd
->sock
;
1028 if (hd
->uri
->use_tls
)
1030 cookie
->tls_session
= tls_session
;
1031 hd
->write_cookie
= cookie
;
1034 hd
->fp_write
= es_fopencookie (cookie
, "w", cookie_functions
);
1038 err
= gpg_error_from_syserror ();
1040 else if (es_fputs (request
, hd
->fp_write
) || es_fflush (hd
->fp_write
))
1041 err
= gpg_error_from_syserror ();
1048 #else /*!HTTP_USE_ESTREAM*/
1049 /* We send out the start of the request through our own send
1050 function and only then assign a stdio stream. This allows for
1051 better error reporting that through standard stdio means. */
1052 err
= write_server (hd
->sock
, request
, strlen (request
));
1055 hd
->fp_write
= fdopen (hd
->sock
, "w");
1057 err
= gpg_error_from_syserror ();
1059 #endif /*!HTTP_USE_ESTREAM*/
1063 xfree (proxy_authstr
);
1070 * Build the relative path from the parsed URI. Minimal
1071 * implementation. May return NULL in case of memory failure; errno
1072 * is then set accordingly.
1075 build_rel_path (parsed_uri_t uri
)
1081 /* Count the needed space. */
1082 n
= insert_escapes (NULL
, uri
->path
, "%;?&");
1083 /* TODO: build params. */
1084 for (r
= uri
->query
; r
; r
= r
->next
)
1087 n
+= insert_escapes (NULL
, r
->name
, "%;?&=");
1091 n
+= insert_escapes (NULL
, r
->value
, "%;?&=");
1096 /* Now allocate and copy. */
1097 p
= rel_path
= xtrymalloc (n
);
1100 n
= insert_escapes (p
, uri
->path
, "%;?&");
1102 /* TODO: add params. */
1103 for (r
= uri
->query
; r
; r
= r
->next
)
1105 *p
++ = r
== uri
->query
? '?' : '&';
1106 n
= insert_escapes (p
, r
->name
, "%;?&=");
1111 /* TODO: Use valuelen. */
1112 n
= insert_escapes (p
, r
->value
, "%;?&=");
1123 Same as fgets() but if the buffer is too short a larger one will be
1124 allocated up to some limit *MAX_LENGTH. A line is considered a
1125 byte stream ending in a LF. Returns the length of the line. EOF is
1126 indicated by a line of length zero. The last LF may be missing due
1127 to an EOF. If MAX_LENGTH is zero on return, the line has been
1128 truncated. If the returned buffer is NULL, not enough memory was
1129 enable to increase it, the return value will also be 0 and some
1130 bytes might have been lost which should be no problem becuase
1131 out-of-memory is pretty fatal for most applications.
1133 If a line has been truncated, the file pointer is internally moved
1134 forward to the end of the line.
1136 Note: The returned buffer is allocated with enough extra space to
1141 #ifdef HTTP_USE_ESTREAM
1146 char **addr_of_buffer
,
1147 size_t *length_of_buffer
, size_t *max_length
)
1150 char *buffer
= *addr_of_buffer
;
1151 size_t length
= *length_of_buffer
;
1153 size_t maxlen
= *max_length
;
1156 if (!buffer
) /* Must allocate a new buffer. */
1159 buffer
= xtrymalloc (length
);
1160 *addr_of_buffer
= buffer
;
1163 *length_of_buffer
= *max_length
= 0;
1166 *length_of_buffer
= length
;
1169 length
-= 3; /* Reserve 3 bytes (cr,lf,eol). */
1171 while ((c
= P_ES(getc
) (fp
)) != EOF
)
1173 if (nbytes
== length
) /* Increase the buffer. */
1175 if (length
> maxlen
) /* Limit reached. */
1177 /* Skip the rest of the line. */
1178 while (c
!= '\n' && (c
= P_ES(getc
) (fp
)) != EOF
)
1180 *p
++ = '\n'; /* Always append a LF (we reserved some space). */
1182 *max_length
= 0; /* Indicate truncation */
1183 break; /*(the while loop)*/
1185 length
+= 3; /* Adjust for the reserved bytes. */
1186 length
+= length
< 1024 ? 256 : 1024;
1187 *addr_of_buffer
= xtryrealloc (buffer
, length
);
1188 if (!*addr_of_buffer
)
1190 int save_errno
= errno
;
1192 *length_of_buffer
= *max_length
= 0;
1196 buffer
= *addr_of_buffer
;
1197 *length_of_buffer
= length
;
1198 length
-= 3; /* And re-adjust for the reservation. */
1199 p
= buffer
+ nbytes
;
1206 *p
= 0; /* Make sure the line is a string. */
1212 /* Transform a header name into a standard capitalized format; e.g.
1213 "Content-Type". Conversion stops at the colon. As usual we don't
1214 use the localized versions of ctype.h. */
1216 capitalize_header_name (char *name
)
1220 for (; *name
&& *name
!= ':'; name
++)
1226 if (*name
>= 'a' && *name
<= 'z')
1227 *name
= *name
- 'a' + 'A';
1230 else if (*name
>= 'A' && *name
<= 'Z')
1231 *name
= *name
- 'A' + 'a';
1236 /* Store an HTTP header line in LINE away. Line continuation is
1237 supported as well as merging of headers with the same name. This
1238 function may modify LINE. */
1240 store_header (http_t hd
, char *line
)
1247 if (n
&& line
[n
-1] == '\n')
1250 if (n
&& line
[n
-1] == '\r')
1253 if (!n
) /* we are never called to hit this. */
1254 return gpg_error (GPG_ERR_BUG
);
1255 if (*line
== ' ' || *line
== '\t')
1257 /* Continuation. This won't happen too often as it is not
1258 recommended. We use a straightforward implementaion. */
1260 return gpg_error (GPG_ERR_PROTOCOL_VIOLATION
);
1261 n
+= strlen (hd
->headers
->value
);
1262 p
= xtrymalloc (n
+1);
1264 return gpg_error_from_syserror ();
1265 strcpy (stpcpy (p
, hd
->headers
->value
), line
);
1266 xfree (hd
->headers
->value
);
1267 hd
->headers
->value
= p
;
1271 capitalize_header_name (line
);
1272 p
= strchr (line
, ':');
1274 return gpg_error (GPG_ERR_PROTOCOL_VIOLATION
);
1276 while (*p
== ' ' || *p
== '\t')
1280 for (h
=hd
->headers
; h
; h
= h
->next
)
1281 if ( !strcmp (h
->name
, line
) )
1285 /* We have already seen a line with that name. Thus we assume
1286 it is a comma separated list and merge them. */
1287 p
= xtrymalloc (strlen (h
->value
) + 1 + strlen (value
)+ 1);
1289 return gpg_error_from_syserror ();
1290 strcpy (stpcpy (stpcpy (p
, h
->value
), ","), value
);
1296 /* Append a new header. */
1297 h
= xtrymalloc (sizeof *h
+ strlen (line
));
1299 return gpg_error_from_syserror ();
1300 strcpy (h
->name
, line
);
1301 h
->value
= xtrymalloc (strlen (value
)+1);
1305 return gpg_error_from_syserror ();
1307 strcpy (h
->value
, value
);
1308 h
->next
= hd
->headers
;
1315 /* Return the header NAME from the last response. The returned value
1316 is valid as along as HD has not been closed and no othe request has
1317 been send. If the header was not found, NULL is returned. Name
1318 must be canonicalized, that is the first letter of each dash
1319 delimited part must be uppercase and all other letters lowercase.
1320 Note that the context must have been opened with the
1321 HTTP_FLAG_NEED_HEADER. */
1323 http_get_header (http_t hd
, const char *name
)
1327 for (h
=hd
->headers
; h
; h
= h
->next
)
1328 if ( !strcmp (h
->name
, name
) )
1336 * Parse the response from a server.
1337 * Returns: Errorcode and sets some files in the handle
1340 parse_response (http_t hd
)
1342 char *line
, *p
, *p2
;
1345 /* Delete old header lines. */
1348 header_t tmp
= hd
->headers
->next
;
1349 xfree (hd
->headers
->value
);
1350 xfree (hd
->headers
);
1354 /* Wait for the status line. */
1357 maxlen
= MAX_LINELEN
;
1358 len
= my_read_line (hd
->fp_read
, &hd
->buffer
, &hd
->buffer_size
, &maxlen
);
1361 return gpg_error_from_syserror (); /* Out of core. */
1363 return gpg_error (GPG_ERR_TRUNCATED
); /* Line has been truncated. */
1365 return gpg_error (GPG_ERR_EOF
);
1366 if ( (hd
->flags
& HTTP_FLAG_LOG_RESP
) )
1367 log_info ("RESP: `%.*s'\n",
1368 (int)strlen(line
)-(*line
&&line
[1]?2:0),line
);
1372 if ((p
= strchr (line
, '/')))
1374 if (!p
|| strcmp (line
, "HTTP"))
1375 return 0; /* Assume http 0.9. */
1377 if ((p2
= strpbrk (p
, " \t")))
1380 p2
+= strspn (p2
, " \t");
1383 return 0; /* Also assume http 0.9. */
1385 /* TODO: Add HTTP version number check. */
1386 if ((p2
= strpbrk (p
, " \t")))
1388 if (!isdigit ((unsigned int)p
[0]) || !isdigit ((unsigned int)p
[1])
1389 || !isdigit ((unsigned int)p
[2]) || p
[3])
1391 /* Malformed HTTP status code - assume http 0.9. */
1392 hd
->is_http_0_9
= 1;
1393 hd
->status_code
= 200;
1396 hd
->status_code
= atoi (p
);
1398 /* Skip all the header lines and wait for the empty line. */
1401 maxlen
= MAX_LINELEN
;
1402 len
= my_read_line (hd
->fp_read
, &hd
->buffer
, &hd
->buffer_size
, &maxlen
);
1405 return gpg_error_from_syserror (); /* Out of core. */
1406 /* Note, that we can silently ignore truncated lines. */
1408 return gpg_error (GPG_ERR_EOF
);
1409 /* Trim line endings of empty lines. */
1410 if ((*line
== '\r' && line
[1] == '\n') || *line
== '\n')
1412 if ( (hd
->flags
& HTTP_FLAG_LOG_RESP
) )
1413 log_info ("RESP: `%.*s'\n",
1414 (int)strlen(line
)-(*line
&&line
[1]?2:0),line
);
1415 if ( (hd
->flags
& HTTP_FLAG_NEED_HEADER
) && *line
)
1417 gpg_error_t err
= store_header (hd
, line
);
1422 while (len
&& *line
);
1431 struct sockaddr_in mya
;
1432 struct sockaddr_in peer
;
1438 if ((fd
= socket (AF_INET
, SOCK_STREAM
, 0)) == -1)
1440 log_error ("socket() failed: %s\n", strerror (errno
));
1444 if (setsockopt (fd
, SOL_SOCKET
, SO_REUSEADDR
, (byte
*) & i
, sizeof (i
)))
1445 log_info ("setsockopt(SO_REUSEADDR) failed: %s\n", strerror (errno
));
1447 mya
.sin_family
= AF_INET
;
1448 memset (&mya
.sin_addr
, 0, sizeof (mya
.sin_addr
));
1449 mya
.sin_port
= htons (11371);
1451 if (bind (fd
, (struct sockaddr
*) &mya
, sizeof (mya
)))
1453 log_error ("bind to port 11371 failed: %s\n", strerror (errno
));
1460 log_error ("listen failed: %s\n", strerror (errno
));
1470 if (select (fd
+ 1, &rfds
, NULL
, NULL
, NULL
) <= 0)
1471 continue; /* ignore any errors */
1473 if (!FD_ISSET (fd
, &rfds
))
1476 addrlen
= sizeof peer
;
1477 client
= accept (fd
, (struct sockaddr
*) &peer
, &addrlen
);
1479 continue; /* oops */
1481 log_info ("connect from %s\n", inet_ntoa (peer
.sin_addr
));
1490 fp
= fdopen (client
, "r");
1491 while ((c
= getc (fp
)) != EOF
)
1496 sock_close (client
);
1504 /* Actually connect to a server. Returns the file descriptor or -1 on
1505 error. ERRNO is set on error. */
1507 connect_server (const char *server
, unsigned short port
,
1508 unsigned int flags
, const char *srvtag
)
1515 struct srventry
*serverlist
= NULL
;
1517 #ifdef HAVE_W32_SYSTEM
1518 unsigned long inaddr
;
1520 #ifndef HTTP_NO_WSASTARTUP
1523 /* Win32 gethostbyname doesn't handle IP addresses internally, so we
1524 try inet_addr first on that platform only. */
1525 inaddr
= inet_addr(server
);
1526 if ( inaddr
!= INADDR_NONE
)
1528 struct sockaddr_in addr
;
1530 memset(&addr
,0,sizeof(addr
));
1532 sock
= socket(AF_INET
,SOCK_STREAM
,0);
1533 if ( sock
==INVALID_SOCKET
)
1535 log_error("error creating socket: ec=%d\n",(int)WSAGetLastError());
1539 addr
.sin_family
= AF_INET
;
1540 addr
.sin_port
= htons(port
);
1541 memcpy (&addr
.sin_addr
,&inaddr
,sizeof(inaddr
));
1543 if (!connect (sock
,(struct sockaddr
*)&addr
,sizeof(addr
)) )
1548 #endif /*HAVE_W32_SYSTEM*/
1551 /* Do the SRV thing */
1552 if ((flags
& HTTP_FLAG_TRY_SRV
) && srvtag
)
1554 /* We're using SRV, so append the tags. */
1555 if (1+strlen (srvtag
) + 6 + strlen (server
) + 1 <= MAXDNAME
)
1557 char srvname
[MAXDNAME
];
1559 stpcpy (stpcpy (stpcpy (stpcpy (srvname
,"_"), srvtag
),
1561 srvcount
= getsrv (srvname
, &serverlist
);
1564 #endif /*USE_DNS_SRV*/
1568 /* Either we're not using SRV, or the SRV lookup failed. Make
1569 up a fake SRV record. */
1570 serverlist
= xtrycalloc (1, sizeof *serverlist
);
1572 return -1; /* Out of core. */
1573 serverlist
->port
= port
;
1574 strncpy (serverlist
->target
, server
, MAXDNAME
);
1575 serverlist
->target
[MAXDNAME
-1] = '\0';
1579 #ifdef HAVE_GETADDRINFO
1581 for (srv
=0; srv
< srvcount
&& !connected
; srv
++)
1583 struct addrinfo hints
, *res
, *ai
;
1586 sprintf (portstr
, "%hu", port
);
1587 memset (&hints
, 0, sizeof (hints
));
1588 hints
.ai_socktype
= SOCK_STREAM
;
1589 if (getaddrinfo (serverlist
[srv
].target
, portstr
, &hints
, &res
))
1590 continue; /* Not found - try next one. */
1593 for (ai
= res
; ai
&& !connected
; ai
= ai
->ai_next
)
1597 sock
= socket (ai
->ai_family
, ai
->ai_socktype
, ai
->ai_protocol
);
1600 int save_errno
= errno
;
1601 log_error ("error creating socket: %s\n", strerror (errno
));
1608 if (connect (sock
, ai
->ai_addr
, ai
->ai_addrlen
))
1615 #else /* !HAVE_GETADDRINFO */
1617 for (srv
=0; srv
< srvcount
&& !connected
; srv
++)
1620 struct hostent
*host
= NULL
;
1621 struct sockaddr_in addr
;
1623 /* Note: This code is not thread-safe. */
1625 memset (&addr
, 0, sizeof (addr
));
1626 host
= gethostbyname (serverlist
[srv
].target
);
1633 sock
= socket (host
->h_addrtype
, SOCK_STREAM
, 0);
1636 log_error (_("error creating socket: %s\n"), strerror (errno
));
1641 addr
.sin_family
= host
->h_addrtype
;
1642 if (addr
.sin_family
!= AF_INET
)
1644 log_error ("unknown address family for `%s'\n",
1645 serverlist
[srv
].target
);
1649 addr
.sin_port
= htons (serverlist
[srv
].port
);
1650 if (host
->h_length
!= 4)
1652 log_error ("illegal address length for `%s'\n",
1653 serverlist
[srv
].target
);
1658 /* Try all A records until one responds. */
1659 for (i
= 0; host
->h_addr_list
[i
] && !connected
; i
++)
1661 memcpy (&addr
.sin_addr
, host
->h_addr_list
[i
], host
->h_length
);
1662 if (connect (sock
, (struct sockaddr
*) &addr
, sizeof (addr
)))
1671 #endif /* !HAVE_GETADDRINFO */
1677 #ifdef HAVE_W32_SYSTEM
1678 log_error ("can't connect to `%s': %s%sec=%d\n",
1680 hostfound
? "":_("host not found"),
1681 hostfound
? "":" - ", (int)WSAGetLastError());
1683 log_error ("can't connect to `%s': %s\n",
1685 hostfound
? strerror (last_errno
):"host not found");
1697 write_server (int sock
, const char *data
, size_t length
)
1704 #ifdef HAVE_W32_SYSTEM
1707 nwritten
= send (sock
, data
, nleft
, 0);
1708 if ( nwritten
== SOCKET_ERROR
)
1710 log_info ("network write failed: ec=%d\n", (int)WSAGetLastError ());
1711 return gpg_error (GPG_ERR_NETWORK
);
1713 #else /*!HAVE_W32_SYSTEM*/
1714 int nwritten
= write (sock
, data
, nleft
);
1719 if (errno
== EAGAIN
)
1725 select (0, NULL
, NULL
, NULL
, &tv
);
1728 log_info ("network write failed: %s\n", strerror (errno
));
1729 return gpg_error_from_syserror ();
1731 #endif /*!HAVE_W32_SYSTEM*/
1741 #ifdef HTTP_USE_ESTREAM
1742 /* Read handler for estream. */
1744 cookie_read (void *cookie
, void *buffer
, size_t size
)
1746 cookie_t c
= cookie
;
1749 #ifdef HTTP_USE_GNUTLS
1753 nread
= gnutls_record_recv (c
->tls_session
, buffer
, size
);
1756 if (nread
== GNUTLS_E_INTERRUPTED
)
1758 if (nread
== GNUTLS_E_AGAIN
)
1764 select (0, NULL
, NULL
, NULL
, &tv
);
1767 if (nread
== GNUTLS_E_REHANDSHAKE
)
1768 goto again
; /* A client is allowed to just ignore this request. */
1769 log_info ("TLS network read failed: %s\n", gnutls_strerror (nread
));
1775 #endif /*HTTP_USE_GNUTLS*/
1779 #ifdef HAVE_W32_SYSTEM
1780 /* Under Windows we need to use recv for a socket. */
1781 nread
= recv (c
->fd
, buffer
, size
, 0);
1783 nread
= read (c
->fd
, buffer
, size
);
1786 while (nread
== -1 && errno
== EINTR
);
1792 /* Write handler for estream. */
1794 cookie_write (void *cookie
, const void *buffer
, size_t size
)
1796 cookie_t c
= cookie
;
1799 #ifdef HTTP_USE_GNUTLS
1805 nwritten
= gnutls_record_send (c
->tls_session
, buffer
, nleft
);
1808 if (nwritten
== GNUTLS_E_INTERRUPTED
)
1810 if (nwritten
== GNUTLS_E_AGAIN
)
1816 select (0, NULL
, NULL
, NULL
, &tv
);
1819 log_info ("TLS network write failed: %s\n",
1820 gnutls_strerror (nwritten
));
1829 #endif /*HTTP_USE_GNUTLS*/
1831 if ( write_server (c
->fd
, buffer
, size
) )
1843 /* Close handler for estream. */
1845 cookie_close (void *cookie
)
1847 cookie_t c
= cookie
;
1852 #ifdef HTTP_USE_GNUTLS
1853 if (c
->tls_session
&& !c
->keep_socket
)
1855 gnutls_bye (c
->tls_session
, GNUTLS_SHUT_RDWR
);
1857 #endif /*HTTP_USE_GNUTLS*/
1858 if (c
->fd
!= -1 && !c
->keep_socket
)
1864 #endif /*HTTP_USE_ESTREAM*/
1869 /**** Test code ****/
1873 verify_callback (http_t hd
, void *tls_context
, int reserved
)
1875 log_info ("verification of certificates skipped\n");
1882 /* my_gnutls_log (int level, const char *text) */
1884 /* fprintf (stderr, "gnutls:L%d: %s", level, text); */
1888 main (int argc
, char **argv
)
1895 gnutls_session_t tls_session
= NULL
;
1896 #ifdef HTTP_USE_GNUTLS
1897 gnutls_certificate_credentials certcred
;
1898 const int certprio
[] = { GNUTLS_CRT_X509
, 0 };
1899 #endif /*HTTP_USE_GNUTLS*/
1902 #ifdef HTTP_USE_ESTREAM
1905 log_set_prefix ("http-test", 1 | 4);
1908 /*start_server (); */
1914 fprintf (stderr
, "usage: http-test uri\n");
1920 #ifdef HTTP_USE_GNUTLS
1921 rc
= gnutls_global_init ();
1923 log_error ("gnutls_global_init failed: %s\n", gnutls_strerror (rc
));
1924 rc
= gnutls_certificate_allocate_credentials (&certcred
);
1926 log_error ("gnutls_certificate_allocate_credentials failed: %s\n",
1927 gnutls_strerror (rc
));
1928 /* rc = gnutls_certificate_set_x509_trust_file */
1929 /* (certcred, "ca.pem", GNUTLS_X509_FMT_PEM); */
1931 /* log_error ("gnutls_certificate_set_x509_trust_file failed: %s\n", */
1932 /* gnutls_strerror (rc)); */
1933 rc
= gnutls_init (&tls_session
, GNUTLS_CLIENT
);
1935 log_error ("gnutls_init failed: %s\n", gnutls_strerror (rc
));
1936 rc
= gnutls_set_default_priority (tls_session
);
1938 log_error ("gnutls_set_default_priority failed: %s\n",
1939 gnutls_strerror (rc
));
1940 rc
= gnutls_certificate_type_set_priority (tls_session
, certprio
);
1942 log_error ("gnutls_certificate_type_set_priority failed: %s\n",
1943 gnutls_strerror (rc
));
1944 rc
= gnutls_credentials_set (tls_session
, GNUTLS_CRD_CERTIFICATE
, certcred
);
1946 log_error ("gnutls_credentials_set failed: %s\n", gnutls_strerror (rc
));
1947 /* gnutls_global_set_log_function (my_gnutls_log); */
1948 /* gnutls_global_set_log_level (4); */
1950 http_register_tls_callback (verify_callback
);
1951 #endif /*HTTP_USE_GNUTLS*/
1953 rc
= http_parse_uri (&uri
, *argv
);
1956 log_error ("`%s': %s\n", *argv
, gpg_strerror (rc
));
1957 http_release_parsed_uri (uri
);
1961 printf ("Scheme: %s\n", uri
->scheme
);
1962 printf ("Host : %s\n", uri
->host
);
1963 printf ("Port : %u\n", uri
->port
);
1964 printf ("Path : %s\n", uri
->path
);
1965 for (r
= uri
->params
; r
; r
= r
->next
)
1967 printf ("Params: %s", r
->name
);
1970 printf ("=%s", r
->value
);
1971 if (strlen (r
->value
) != r
->valuelen
)
1972 printf (" [real length=%d]", (int) r
->valuelen
);
1976 for (r
= uri
->query
; r
; r
= r
->next
)
1978 printf ("Query : %s", r
->name
);
1981 printf ("=%s", r
->value
);
1982 if (strlen (r
->value
) != r
->valuelen
)
1983 printf (" [real length=%d]", (int) r
->valuelen
);
1987 http_release_parsed_uri (uri
);
1990 rc
= http_open_document (&hd
, *argv
, NULL
,
1991 HTTP_FLAG_NO_SHUTDOWN
| HTTP_FLAG_NEED_HEADER
,
1995 log_error ("can't get `%s': %s\n", *argv
, gpg_strerror (rc
));
1998 log_info ("open_http_document succeeded; status=%u\n",
1999 http_get_status_code (hd
));
2000 for (hdr
= hd
->headers
; hdr
; hdr
= hdr
->next
)
2001 printf ("HDR: %s: %s\n", hdr
->name
, hdr
->value
);
2002 switch (http_get_status_code (hd
))
2005 while ((c
= P_ES(getc
) (http_get_read_ptr (hd
))) != EOF
)
2010 printf ("Redirected to `%s'\n", http_get_header (hd
, "Location"));
2015 #ifdef HTTP_USE_GNUTLS
2016 gnutls_deinit (tls_session
);
2017 gnutls_certificate_free_credentials (certcred
);
2018 gnutls_global_deinit ();
2019 #endif /*HTTP_USE_GNUTLS*/
2028 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"