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
;
312 /* Start a HTTP retrieval and return on success in R_HD a context
313 pointer for completing the the request and to wait for the
316 http_open (http_t
*r_hd
, http_req_t reqtype
, const char *url
,
317 const char *auth
, unsigned int flags
, const char *proxy
,
325 if (!(reqtype
== HTTP_REQ_GET
|| reqtype
== HTTP_REQ_POST
))
326 return gpg_error (GPG_ERR_INV_ARG
);
328 /* Create the handle. */
329 hd
= xtrycalloc (1, sizeof *hd
);
331 return gpg_error_from_syserror ();
333 hd
->req_type
= reqtype
;
335 hd
->tls_context
= tls_context
;
337 err
= http_parse_uri (&hd
->uri
, url
);
339 err
= send_request (hd
, auth
, proxy
);
343 if (!hd
->fp_read
&& !hd
->fp_write
&& hd
->sock
!= -1)
344 sock_close (hd
->sock
);
346 P_ES(fclose
) (hd
->fp_read
);
348 P_ES(fclose
) (hd
->fp_write
);
349 http_release_parsed_uri (hd
->uri
);
359 http_start_data (http_t hd
)
363 #ifdef HTTP_USE_ESTREAM
364 es_fputs ("\r\n", hd
->fp_write
);
365 es_fflush (hd
->fp_write
);
367 fflush (hd
->fp_write
);
368 write_server (hd
->sock
, "\r\n", 2);
373 P_ES(fflush
) (hd
->fp_write
);
378 http_wait_response (http_t hd
)
382 /* Make sure that we are in the data. */
383 http_start_data (hd
);
385 /* We dup the socket, to cope with the fact that fclose closes the
386 underlying socket. In TLS mode we don't do that because we can't
387 close the socket gnutls is working on; instead we make sure that
388 the fclose won't close the socket in this case. */
389 #ifdef HTTP_USE_ESTREAM
390 if (hd
->write_cookie
)
392 /* The write cookie is only set in the TLS case. */
393 cookie_t cookie
= hd
->write_cookie
;
394 cookie
->keep_socket
= 1;
397 #endif /*HTTP_USE_ESTREAM*/
399 hd
->sock
= dup (hd
->sock
);
401 return gpg_error_from_syserror ();
403 P_ES(fclose
) (hd
->fp_write
);
405 #ifdef HTTP_USE_ESTREAM
406 hd
->write_cookie
= NULL
;
409 if (!(hd
->flags
& HTTP_FLAG_NO_SHUTDOWN
))
410 shutdown (hd
->sock
, 1);
413 #ifdef HTTP_USE_ESTREAM
417 cookie
= xtrycalloc (1, sizeof *cookie
);
419 return gpg_error_from_syserror ();
420 cookie
->fd
= hd
->sock
;
421 if (hd
->uri
->use_tls
)
422 cookie
->tls_session
= hd
->tls_context
;
424 hd
->fp_read
= es_fopencookie (cookie
, "r", cookie_functions
);
428 return gpg_error_from_syserror ();
431 #else /*!HTTP_USE_ESTREAM*/
432 hd
->fp_read
= fdopen (hd
->sock
, "r");
434 return gpg_error_from_syserror ();
435 #endif /*!HTTP_USE_ESTREAM*/
437 err
= parse_response (hd
);
442 /* Convenience function to send a request and wait for the response.
443 Closes the handle on error. If PROXY is not NULL, this value will
444 be used as an HTTP proxy and any enabled $http_proxy gets
447 http_open_document (http_t
*r_hd
, const char *document
,
448 const char *auth
, unsigned int flags
, const char *proxy
,
453 err
= http_open (r_hd
, HTTP_REQ_GET
, document
, auth
, flags
,
458 err
= http_wait_response (*r_hd
);
460 http_close (*r_hd
, 0);
467 http_close (http_t hd
, int keep_read_stream
)
471 if (!hd
->fp_read
&& !hd
->fp_write
&& hd
->sock
!= -1)
472 sock_close (hd
->sock
);
473 if (hd
->fp_read
&& !keep_read_stream
)
474 P_ES(fclose
) (hd
->fp_read
);
476 P_ES(fclose
) (hd
->fp_write
);
477 http_release_parsed_uri (hd
->uri
);
480 header_t tmp
= hd
->headers
->next
;
481 xfree (hd
->headers
->value
);
490 #ifdef HTTP_USE_ESTREAM
492 http_get_read_ptr (http_t hd
)
494 return hd
?hd
->fp_read
:NULL
;
497 http_get_write_ptr (http_t hd
)
499 return hd
?hd
->fp_write
:NULL
;
501 #else /*!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 #endif /*!HTTP_USE_ESTREAM*/
514 http_get_status_code (http_t hd
)
516 return hd
?hd
->status_code
:0;
522 * Parse an URI and put the result into the newly allocated RET_URI.
523 * The caller must always use release_parsed_uri() to releases the
524 * resources (even on error).
527 http_parse_uri (parsed_uri_t
* ret_uri
, const char *uri
)
529 *ret_uri
= xcalloc (1, sizeof **ret_uri
+ strlen (uri
));
530 strcpy ((*ret_uri
)->buffer
, uri
);
531 return do_parse_uri (*ret_uri
, 0);
535 http_release_parsed_uri (parsed_uri_t uri
)
541 for (r
= uri
->query
; r
; r
= r2
)
552 do_parse_uri (parsed_uri_t uri
, int only_local_part
)
555 char *p
, *p2
, *p3
, *pp
;
559 n
= strlen (uri
->buffer
);
561 /* Initialize all fields to an empty string or an empty list. */
562 uri
->scheme
= uri
->host
= uri
->path
= p
+ n
;
564 uri
->params
= uri
->query
= NULL
;
567 /* A quick validity check. */
568 if (strspn (p
, VALID_URI_CHARS
) != n
)
569 return gpg_error (GPG_ERR_BAD_URI
); /* Invalid characters found. */
571 if (!only_local_part
)
573 /* Find the scheme. */
574 if (!(p2
= strchr (p
, ':')) || p2
== p
)
575 return gpg_error (GPG_ERR_BAD_URI
); /* No scheme. */
577 for (pp
=p
; *pp
; pp
++)
578 *pp
= tolower (*(unsigned char*)pp
);
580 if (!strcmp (uri
->scheme
, "http"))
582 #ifdef HTTP_USE_GNUTLS
583 else if (!strcmp (uri
->scheme
, "https"))
590 return gpg_error (GPG_ERR_INV_URI
); /* Unsupported scheme */
594 /* Find the hostname */
596 return gpg_error (GPG_ERR_INV_URI
); /* Does not start with a slash. */
599 if (*p
== '/') /* There seems to be a hostname. */
602 if ((p2
= strchr (p
, '/')))
605 /* Check for username/password encoding */
606 if ((p3
= strchr (p
, '@')))
613 for (pp
=p
; *pp
; pp
++)
614 *pp
= tolower (*(unsigned char*)pp
);
616 if ((p3
= strchr (p
, ':')))
619 uri
->port
= atoi (p3
);
623 if ((n
= remove_escapes (uri
->host
)) < 0)
624 return gpg_error (GPG_ERR_BAD_URI
);
626 return gpg_error (GPG_ERR_BAD_URI
); /* Hostname incudes a Nul. */
629 } /* End global URI part. */
631 /* Parse the pathname part */
633 return 0; /* We don't have a path. Okay. */
635 /* TODO: Here we have to check params. */
637 /* Do we have a query part? */
638 if ((p2
= strchr (p
, '?')))
642 if ((n
= remove_escapes (p
)) < 0)
643 return gpg_error (GPG_ERR_BAD_URI
);
645 return gpg_error (GPG_ERR_BAD_URI
); /* Path includes a Nul. */
649 return 0; /* We don't have a query string. Okay. */
651 /* Now parse the query string. */
657 if ((p2
= strchr (p
, '&')))
659 if (!(elem
= parse_tuple (p
)))
660 return gpg_error (GPG_ERR_BAD_URI
);
674 * Remove all %xx escapes; this is done in-place. Returns: New length
678 remove_escapes (char *string
)
681 unsigned char *p
, *s
;
683 for (p
= s
= (unsigned char*)string
; *s
; s
++)
687 if (s
[1] && s
[2] && isxdigit (s
[1]) && isxdigit (s
[2]))
690 *p
= *s
>= '0' && *s
<= '9' ? *s
- '0' :
691 *s
>= 'A' && *s
<= 'F' ? *s
- 'A' + 10 : *s
- 'a' + 10;
694 *p
|= *s
>= '0' && *s
<= '9' ? *s
- '0' :
695 *s
>= 'A' && *s
<= 'F' ? *s
- 'A' + 10 : *s
- 'a' + 10;
708 return -1; /* Bad URI. */
717 *p
= 0; /* Make sure to keep a string terminator. */
723 insert_escapes (char *buffer
, const char *string
,
726 const unsigned char *s
= (const unsigned char*)string
;
731 if (strchr (VALID_URI_CHARS
, *s
) && !strchr (special
, *s
))
734 *(unsigned char*)buffer
++ = *s
;
741 sprintf (buffer
, "%%%02X", *s
);
751 /* Allocate a new string from STRING using standard HTTP escaping as
752 well as escaping of characters given in SPECIALS. A common pattern
753 for SPECIALS is "%;?&=". However it depends on the needs, for
754 example "+" and "/: often needs to be escaped too. Returns NULL on
755 failure and sets ERRNO. */
757 http_escape_string (const char *string
, const char *specials
)
762 n
= insert_escapes (NULL
, string
, specials
);
763 buf
= xtrymalloc (n
+1);
766 insert_escapes (buf
, string
, specials
);
775 parse_tuple (char *string
)
782 if ((p2
= strchr (p
, '=')))
784 if ((n
= remove_escapes (p
)) < 0)
785 return NULL
; /* Bad URI. */
787 return NULL
; /* Name with a Nul in it. */
788 tuple
= xtrycalloc (1, sizeof *tuple
);
790 return NULL
; /* Out of core. */
792 if (!p2
) /* We have only the name, so we assume an empty value string. */
794 tuple
->value
= p
+ strlen (p
);
796 tuple
->no_value
= 1; /* Explicitly mark that we have seen no '='. */
798 else /* Name and value. */
800 if ((n
= remove_escapes (p2
)) < 0)
803 return NULL
; /* Bad URI. */
813 * Send a HTTP request to the server
814 * Returns 0 if the request was successful
817 send_request (http_t hd
, const char *auth
, const char *proxy
)
819 gnutls_session_t tls_session
;
824 const char *http_proxy
= NULL
;
825 char *proxy_authstr
= NULL
;
826 char *authstr
= NULL
;
829 tls_session
= hd
->tls_context
;
830 if (hd
->uri
->use_tls
&& !tls_session
)
832 log_error ("TLS requested but no GNUTLS context provided\n");
833 return gpg_error (GPG_ERR_INTERNAL
);
836 server
= *hd
->uri
->host
? hd
->uri
->host
: "localhost";
837 port
= hd
->uri
->port
? hd
->uri
->port
: 80;
839 if ( (proxy
&& *proxy
)
840 || ( (hd
->flags
& HTTP_FLAG_TRY_PROXY
)
841 && (http_proxy
= getenv (HTTP_PROXY_ENV
))
849 err
= http_parse_uri (&uri
, http_proxy
);
852 log_error ("invalid HTTP proxy (%s): %s\n",
853 http_proxy
, gpg_strerror (err
));
854 http_release_parsed_uri (uri
);
855 return gpg_error (GPG_ERR_CONFIGURATION
);
861 remove_escapes (uri
->auth
);
862 proxy_authstr
= make_header_line ("Proxy-Authorization: Basic ",
864 uri
->auth
, strlen(uri
->auth
));
867 err
= gpg_error_from_syserror ();
868 http_release_parsed_uri (uri
);
873 hd
->sock
= connect_server (*uri
->host
? uri
->host
: "localhost",
874 uri
->port
? uri
->port
: 80,
875 hd
->flags
, hd
->uri
->scheme
);
877 http_release_parsed_uri (uri
);
881 hd
->sock
= connect_server (server
, port
, hd
->flags
, hd
->uri
->scheme
);
887 xfree (proxy_authstr
);
889 ? gpg_error_from_errno (save_errno
)
890 : gpg_error (GPG_ERR_NOT_FOUND
));
893 #ifdef HTTP_USE_GNUTLS
894 if (hd
->uri
->use_tls
)
898 gnutls_transport_set_ptr (tls_session
, (gnutls_transport_ptr_t
)hd
->sock
);
901 rc
= gnutls_handshake (tls_session
);
903 while (rc
== GNUTLS_E_INTERRUPTED
|| rc
== GNUTLS_E_AGAIN
);
906 log_info ("TLS handshake failed: %s\n", gnutls_strerror (rc
));
907 xfree (proxy_authstr
);
908 return gpg_error (GPG_ERR_NETWORK
);
913 err
= tls_callback (hd
, tls_session
, 0);
916 log_info ("TLS connection authentication failed: %s\n",
918 xfree (proxy_authstr
);
923 #endif /*HTTP_USE_GNUTLS*/
925 if (auth
|| hd
->uri
->auth
)
931 myauth
= xtrystrdup (auth
);
934 xfree (proxy_authstr
);
935 return gpg_error_from_syserror ();
937 remove_escapes (myauth
);
941 remove_escapes (hd
->uri
->auth
);
942 myauth
= hd
->uri
->auth
;
945 authstr
= make_header_line ("Authorization: Basic %s", "\r\n",
946 myauth
, strlen (myauth
));
952 xfree (proxy_authstr
);
953 return gpg_error_from_syserror ();
957 p
= build_rel_path (hd
->uri
);
959 return gpg_error_from_syserror ();
961 request
= xtrymalloc (2 * strlen (server
)
963 + (authstr
?strlen(authstr
):0)
964 + (proxy_authstr
?strlen(proxy_authstr
):0)
968 err
= gpg_error_from_syserror ();
971 xfree (proxy_authstr
);
975 if (http_proxy
&& *http_proxy
)
977 sprintf (request
, "%s http://%s:%hu%s%s HTTP/1.0\r\n%s%s",
978 hd
->req_type
== HTTP_REQ_GET
? "GET" :
979 hd
->req_type
== HTTP_REQ_HEAD
? "HEAD" :
980 hd
->req_type
== HTTP_REQ_POST
? "POST" : "OOPS",
981 server
, port
, *p
== '/' ? "" : "/", p
,
982 authstr
? authstr
: "",
983 proxy_authstr
? proxy_authstr
: "");
992 sprintf (portstr
, ":%u", port
);
994 sprintf (request
, "%s %s%s HTTP/1.0\r\nHost: %s%s\r\n%s",
995 hd
->req_type
== HTTP_REQ_GET
? "GET" :
996 hd
->req_type
== HTTP_REQ_HEAD
? "HEAD" :
997 hd
->req_type
== HTTP_REQ_POST
? "POST" : "OOPS",
998 *p
== '/' ? "" : "/", p
, server
, portstr
,
999 authstr
? authstr
:"");
1004 #ifdef HTTP_USE_ESTREAM
1005 /* First setup estream so that we can write even the first line
1006 using estream. This is also required for the sake of gnutls. */
1010 cookie
= xtrycalloc (1, sizeof *cookie
);
1013 err
= gpg_error_from_syserror ();
1016 cookie
->fd
= hd
->sock
;
1017 if (hd
->uri
->use_tls
)
1019 cookie
->tls_session
= tls_session
;
1020 hd
->write_cookie
= cookie
;
1023 hd
->fp_write
= es_fopencookie (cookie
, "w", cookie_functions
);
1027 err
= gpg_error_from_syserror ();
1029 else if (es_fputs (request
, hd
->fp_write
) || es_fflush (hd
->fp_write
))
1030 err
= gpg_error_from_syserror ();
1037 #else /*!HTTP_USE_ESTREAM*/
1038 /* We send out the start of the request through our own send
1039 function and only then assign a stdio stream. This allows for
1040 better error reporting that through standard stdio means. */
1041 err
= write_server (hd
->sock
, request
, strlen (request
));
1044 hd
->fp_write
= fdopen (hd
->sock
, "w");
1046 err
= gpg_error_from_syserror ();
1048 #endif /*!HTTP_USE_ESTREAM*/
1052 xfree (proxy_authstr
);
1059 * Build the relative path from the parsed URI. Minimal
1060 * implementation. May return NULL in case of memory failure; errno
1061 * is then set accordingly.
1064 build_rel_path (parsed_uri_t uri
)
1070 /* Count the needed space. */
1071 n
= insert_escapes (NULL
, uri
->path
, "%;?&");
1072 /* TODO: build params. */
1073 for (r
= uri
->query
; r
; r
= r
->next
)
1076 n
+= insert_escapes (NULL
, r
->name
, "%;?&=");
1080 n
+= insert_escapes (NULL
, r
->value
, "%;?&=");
1085 /* Now allocate and copy. */
1086 p
= rel_path
= xtrymalloc (n
);
1089 n
= insert_escapes (p
, uri
->path
, "%;?&");
1091 /* TODO: add params. */
1092 for (r
= uri
->query
; r
; r
= r
->next
)
1094 *p
++ = r
== uri
->query
? '?' : '&';
1095 n
= insert_escapes (p
, r
->name
, "%;?&=");
1100 /* TODO: Use valuelen. */
1101 n
= insert_escapes (p
, r
->value
, "%;?&=");
1112 Same as fgets() but if the buffer is too short a larger one will be
1113 allocated up to some limit *MAX_LENGTH. A line is considered a
1114 byte stream ending in a LF. Returns the length of the line. EOF is
1115 indicated by a line of length zero. The last LF may be missing due
1116 to an EOF. If MAX_LENGTH is zero on return, the line has been
1117 truncated. If the returned buffer is NULL, not enough memory was
1118 enable to increase it, the return value will also be 0 and some
1119 bytes might have been lost which should be no problem becuase
1120 out-of-memory is pretty fatal for most applications.
1122 If a line has been truncated, the file pointer is internally moved
1123 forward to the end of the line.
1125 Note: The returned buffer is allocated with enough extra space to
1130 #ifdef HTTP_USE_ESTREAM
1135 char **addr_of_buffer
,
1136 size_t *length_of_buffer
, size_t *max_length
)
1139 char *buffer
= *addr_of_buffer
;
1140 size_t length
= *length_of_buffer
;
1142 size_t maxlen
= *max_length
;
1145 if (!buffer
) /* Must allocate a new buffer. */
1148 buffer
= xtrymalloc (length
);
1149 *addr_of_buffer
= buffer
;
1152 *length_of_buffer
= *max_length
= 0;
1155 *length_of_buffer
= length
;
1158 length
-= 3; /* Reserve 3 bytes (cr,lf,eol). */
1160 while ((c
= P_ES(getc
) (fp
)) != EOF
)
1162 if (nbytes
== length
) /* Increase the buffer. */
1164 if (length
> maxlen
) /* Limit reached. */
1166 /* Skip the rest of the line. */
1167 while (c
!= '\n' && (c
= P_ES(getc
) (fp
)) != EOF
)
1169 *p
++ = '\n'; /* Always append a LF (we reserved some space). */
1171 *max_length
= 0; /* Indicate truncation */
1172 break; /*(the while loop)*/
1174 length
+= 3; /* Adjust for the reserved bytes. */
1175 length
+= length
< 1024 ? 256 : 1024;
1176 *addr_of_buffer
= xtryrealloc (buffer
, length
);
1177 if (!*addr_of_buffer
)
1179 int save_errno
= errno
;
1181 *length_of_buffer
= *max_length
= 0;
1185 buffer
= *addr_of_buffer
;
1186 *length_of_buffer
= length
;
1187 length
-= 3; /* And re-adjust for the reservation. */
1188 p
= buffer
+ nbytes
;
1195 *p
= 0; /* Make sure the line is a string. */
1201 /* Transform a header name into a standard capitalized format; e.g.
1202 "Content-Type". Conversion stops at the colon. As usual we don't
1203 use the localized versions of ctype.h. */
1205 capitalize_header_name (char *name
)
1209 for (; *name
&& *name
!= ':'; name
++)
1215 if (*name
>= 'a' && *name
<= 'z')
1216 *name
= *name
- 'a' + 'A';
1219 else if (*name
>= 'A' && *name
<= 'Z')
1220 *name
= *name
- 'A' + 'a';
1225 /* Store an HTTP header line in LINE away. Line continuation is
1226 supported as well as merging of headers with the same name. This
1227 function may modify LINE. */
1229 store_header (http_t hd
, char *line
)
1236 if (n
&& line
[n
-1] == '\n')
1239 if (n
&& line
[n
-1] == '\r')
1242 if (!n
) /* we are never called to hit this. */
1243 return gpg_error (GPG_ERR_BUG
);
1244 if (*line
== ' ' || *line
== '\t')
1246 /* Continuation. This won't happen too often as it is not
1247 recommended. We use a straightforward implementaion. */
1249 return gpg_error (GPG_ERR_PROTOCOL_VIOLATION
);
1250 n
+= strlen (hd
->headers
->value
);
1251 p
= xtrymalloc (n
+1);
1253 return gpg_error_from_syserror ();
1254 strcpy (stpcpy (p
, hd
->headers
->value
), line
);
1255 xfree (hd
->headers
->value
);
1256 hd
->headers
->value
= p
;
1260 capitalize_header_name (line
);
1261 p
= strchr (line
, ':');
1263 return gpg_error (GPG_ERR_PROTOCOL_VIOLATION
);
1265 while (*p
== ' ' || *p
== '\t')
1269 for (h
=hd
->headers
; h
; h
= h
->next
)
1270 if ( !strcmp (h
->name
, line
) )
1274 /* We have already seen a line with that name. Thus we assume
1275 it is a comma separated list and merge them. */
1276 p
= xtrymalloc (strlen (h
->value
) + 1 + strlen (value
)+ 1);
1278 return gpg_error_from_syserror ();
1279 strcpy (stpcpy (stpcpy (p
, h
->value
), ","), value
);
1285 /* Append a new header. */
1286 h
= xtrymalloc (sizeof *h
+ strlen (line
));
1288 return gpg_error_from_syserror ();
1289 strcpy (h
->name
, line
);
1290 h
->value
= xtrymalloc (strlen (value
)+1);
1294 return gpg_error_from_syserror ();
1296 strcpy (h
->value
, value
);
1297 h
->next
= hd
->headers
;
1304 /* Return the header NAME from the last response. The returned value
1305 is valid as along as HD has not been closed and no othe request has
1306 been send. If the header was not found, NULL is returned. Name
1307 must be canonicalized, that is the first letter of each dash
1308 delimited part must be uppercase and all other letters lowercase.
1309 Note that the context must have been opened with the
1310 HTTP_FLAG_NEED_HEADER. */
1312 http_get_header (http_t hd
, const char *name
)
1316 for (h
=hd
->headers
; h
; h
= h
->next
)
1317 if ( !strcmp (h
->name
, name
) )
1325 * Parse the response from a server.
1326 * Returns: Errorcode and sets some files in the handle
1329 parse_response (http_t hd
)
1331 char *line
, *p
, *p2
;
1334 /* Delete old header lines. */
1337 header_t tmp
= hd
->headers
->next
;
1338 xfree (hd
->headers
->value
);
1339 xfree (hd
->headers
);
1343 /* Wait for the status line. */
1346 maxlen
= MAX_LINELEN
;
1347 len
= my_read_line (hd
->fp_read
, &hd
->buffer
, &hd
->buffer_size
, &maxlen
);
1350 return gpg_error_from_syserror (); /* Out of core. */
1352 return gpg_error (GPG_ERR_TRUNCATED
); /* Line has been truncated. */
1354 return gpg_error (GPG_ERR_EOF
);
1355 if ( (hd
->flags
& HTTP_FLAG_LOG_RESP
) )
1356 log_info ("RESP: `%.*s'\n",
1357 (int)strlen(line
)-(*line
&&line
[1]?2:0),line
);
1361 if ((p
= strchr (line
, '/')))
1363 if (!p
|| strcmp (line
, "HTTP"))
1364 return 0; /* Assume http 0.9. */
1366 if ((p2
= strpbrk (p
, " \t")))
1369 p2
+= strspn (p2
, " \t");
1372 return 0; /* Also assume http 0.9. */
1374 /* TODO: Add HTTP version number check. */
1375 if ((p2
= strpbrk (p
, " \t")))
1377 if (!isdigit ((unsigned int)p
[0]) || !isdigit ((unsigned int)p
[1])
1378 || !isdigit ((unsigned int)p
[2]) || p
[3])
1380 /* Malformed HTTP status code - assume http 0.9. */
1381 hd
->is_http_0_9
= 1;
1382 hd
->status_code
= 200;
1385 hd
->status_code
= atoi (p
);
1387 /* Skip all the header lines and wait for the empty line. */
1390 maxlen
= MAX_LINELEN
;
1391 len
= my_read_line (hd
->fp_read
, &hd
->buffer
, &hd
->buffer_size
, &maxlen
);
1394 return gpg_error_from_syserror (); /* Out of core. */
1395 /* Note, that we can silently ignore truncated lines. */
1397 return gpg_error (GPG_ERR_EOF
);
1398 /* Trim line endings of empty lines. */
1399 if ((*line
== '\r' && line
[1] == '\n') || *line
== '\n')
1401 if ( (hd
->flags
& HTTP_FLAG_LOG_RESP
) )
1402 log_info ("RESP: `%.*s'\n",
1403 (int)strlen(line
)-(*line
&&line
[1]?2:0),line
);
1404 if ( (hd
->flags
& HTTP_FLAG_NEED_HEADER
) && *line
)
1406 gpg_error_t err
= store_header (hd
, line
);
1411 while (len
&& *line
);
1420 struct sockaddr_in mya
;
1421 struct sockaddr_in peer
;
1427 if ((fd
= socket (AF_INET
, SOCK_STREAM
, 0)) == -1)
1429 log_error ("socket() failed: %s\n", strerror (errno
));
1433 if (setsockopt (fd
, SOL_SOCKET
, SO_REUSEADDR
, (byte
*) & i
, sizeof (i
)))
1434 log_info ("setsockopt(SO_REUSEADDR) failed: %s\n", strerror (errno
));
1436 mya
.sin_family
= AF_INET
;
1437 memset (&mya
.sin_addr
, 0, sizeof (mya
.sin_addr
));
1438 mya
.sin_port
= htons (11371);
1440 if (bind (fd
, (struct sockaddr
*) &mya
, sizeof (mya
)))
1442 log_error ("bind to port 11371 failed: %s\n", strerror (errno
));
1449 log_error ("listen failed: %s\n", strerror (errno
));
1459 if (select (fd
+ 1, &rfds
, NULL
, NULL
, NULL
) <= 0)
1460 continue; /* ignore any errors */
1462 if (!FD_ISSET (fd
, &rfds
))
1465 addrlen
= sizeof peer
;
1466 client
= accept (fd
, (struct sockaddr
*) &peer
, &addrlen
);
1468 continue; /* oops */
1470 log_info ("connect from %s\n", inet_ntoa (peer
.sin_addr
));
1479 fp
= fdopen (client
, "r");
1480 while ((c
= getc (fp
)) != EOF
)
1485 sock_close (client
);
1493 /* Actually connect to a server. Returns the file descripto or -1 on
1494 error. ERRNO is set on error. */
1496 connect_server (const char *server
, unsigned short port
,
1497 unsigned int flags
, const char *srvtag
)
1504 struct srventry
*serverlist
= NULL
;
1506 #ifdef HAVE_W32_SYSTEM
1507 unsigned long inaddr
;
1509 #ifndef HTTP_NO_WSASTARTUP
1512 /* Win32 gethostbyname doesn't handle IP addresses internally, so we
1513 try inet_addr first on that platform only. */
1514 inaddr
= inet_addr(server
);
1515 if ( inaddr
!= INADDR_NONE
)
1517 struct sockaddr_in addr
;
1519 memset(&addr
,0,sizeof(addr
));
1521 sock
= socket(AF_INET
,SOCK_STREAM
,0);
1522 if ( sock
==INVALID_SOCKET
)
1524 log_error("error creating socket: ec=%d\n",(int)WSAGetLastError());
1528 addr
.sin_family
= AF_INET
;
1529 addr
.sin_port
= htons(port
);
1530 memcpy (&addr
.sin_addr
,&inaddr
,sizeof(inaddr
));
1532 if (!connect (sock
,(struct sockaddr
*)&addr
,sizeof(addr
)) )
1537 #endif /*HAVE_W32_SYSTEM*/
1540 /* Do the SRV thing */
1541 if ((flags
& HTTP_FLAG_TRY_SRV
) && srvtag
)
1543 /* We're using SRV, so append the tags. */
1544 if (1+strlen (srvtag
) + 6 + strlen (server
) + 1 <= MAXDNAME
)
1546 char srvname
[MAXDNAME
];
1548 stpcpy (stpcpy (stpcpy (stpcpy (srvname
,"_"), srvtag
),
1550 srvcount
= getsrv (srvname
, &serverlist
);
1553 #endif /*USE_DNS_SRV*/
1557 /* Either we're not using SRV, or the SRV lookup failed. Make
1558 up a fake SRV record. */
1559 serverlist
= xtrycalloc (1, sizeof *serverlist
);
1561 return -1; /* Out of core. */
1562 serverlist
->port
= port
;
1563 strncpy (serverlist
->target
, server
, MAXDNAME
);
1564 serverlist
->target
[MAXDNAME
-1] = '\0';
1568 #ifdef HAVE_GETADDRINFO
1570 for (srv
=0; srv
< srvcount
&& !connected
; srv
++)
1572 struct addrinfo hints
, *res
, *ai
;
1575 sprintf (portstr
, "%hu", port
);
1576 memset (&hints
, 0, sizeof (hints
));
1577 hints
.ai_socktype
= SOCK_STREAM
;
1578 if (getaddrinfo (serverlist
[srv
].target
, portstr
, &hints
, &res
))
1579 continue; /* Not found - try next one. */
1582 for (ai
= res
; ai
&& !connected
; ai
= ai
->ai_next
)
1586 sock
= socket (ai
->ai_family
, ai
->ai_socktype
, ai
->ai_protocol
);
1589 int save_errno
= errno
;
1590 log_error ("error creating socket: %s\n", strerror (errno
));
1597 if (connect (sock
, ai
->ai_addr
, ai
->ai_addrlen
))
1604 #else /* !HAVE_GETADDRINFO */
1606 for (srv
=0; srv
< srvcount
&& !connected
; srv
++)
1609 struct hostent
*host
= NULL
;
1610 struct sockaddr_in addr
;
1612 /* Note: This code is not thread-safe. */
1614 memset (&addr
, 0, sizeof (addr
));
1615 host
= gethostbyname (serverlist
[srv
].target
);
1622 sock
= socket (host
->h_addrtype
, SOCK_STREAM
, 0);
1625 log_error (_("error creating socket: %s\n"), strerror (errno
));
1630 addr
.sin_family
= host
->h_addrtype
;
1631 if (addr
.sin_family
!= AF_INET
)
1633 log_error ("unknown address family for `%s'\n",
1634 serverlist
[srv
].target
);
1638 addr
.sin_port
= htons (serverlist
[srv
].port
);
1639 if (host
->h_length
!= 4)
1641 log_error ("illegal address length for `%s'\n",
1642 serverlist
[srv
].target
);
1647 /* Try all A records until one responds. */
1648 for (i
= 0; host
->h_addr_list
[i
] && !connected
; i
++)
1650 memcpy (&addr
.sin_addr
, host
->h_addr_list
[i
], host
->h_length
);
1651 if (connect (sock
, (struct sockaddr
*) &addr
, sizeof (addr
)))
1660 #endif /* !HAVE_GETADDRINFO */
1666 #ifdef HAVE_W32_SYSTEM
1667 log_error ("can't connect to `%s': %s%sec=%d\n",
1669 hostfound
? "":_("host not found"),
1670 hostfound
? "":" - ", (int)WSAGetLastError());
1672 log_error ("can't connect to `%s': %s\n",
1674 hostfound
? strerror (last_errno
):"host not found");
1686 write_server (int sock
, const char *data
, size_t length
)
1693 #ifdef HAVE_W32_SYSTEM
1696 nwritten
= send (sock
, data
, nleft
, 0);
1697 if ( nwritten
== SOCKET_ERROR
)
1699 log_info ("network write failed: ec=%d\n", (int)WSAGetLastError ());
1700 return gpg_error (GPG_ERR_NETWORK
);
1702 #else /*!HAVE_W32_SYSTEM*/
1703 int nwritten
= write (sock
, data
, nleft
);
1708 if (errno
== EAGAIN
)
1714 select (0, NULL
, NULL
, NULL
, &tv
);
1717 log_info ("network write failed: %s\n", strerror (errno
));
1718 return gpg_error_from_syserror ();
1720 #endif /*!HAVE_W32_SYSTEM*/
1730 #ifdef HTTP_USE_ESTREAM
1731 /* Read handler for estream. */
1733 cookie_read (void *cookie
, void *buffer
, size_t size
)
1735 cookie_t c
= cookie
;
1738 #ifdef HTTP_USE_GNUTLS
1742 nread
= gnutls_record_recv (c
->tls_session
, buffer
, size
);
1745 if (nread
== GNUTLS_E_INTERRUPTED
)
1747 if (nread
== GNUTLS_E_AGAIN
)
1753 select (0, NULL
, NULL
, NULL
, &tv
);
1756 if (nread
== GNUTLS_E_REHANDSHAKE
)
1757 goto again
; /* A client is allowed to just ignore this request. */
1758 log_info ("TLS network read failed: %s\n", gnutls_strerror (nread
));
1764 #endif /*HTTP_USE_GNUTLS*/
1768 nread
= read (c
->fd
, buffer
, size
);
1770 while (nread
== -1 && errno
== EINTR
);
1776 /* Write handler for estream. */
1778 cookie_write (void *cookie
, const void *buffer
, size_t size
)
1780 cookie_t c
= cookie
;
1783 #ifdef HTTP_USE_GNUTLS
1789 nwritten
= gnutls_record_send (c
->tls_session
, buffer
, nleft
);
1792 if (nwritten
== GNUTLS_E_INTERRUPTED
)
1794 if (nwritten
== GNUTLS_E_AGAIN
)
1800 select (0, NULL
, NULL
, NULL
, &tv
);
1803 log_info ("TLS network write failed: %s\n",
1804 gnutls_strerror (nwritten
));
1813 #endif /*HTTP_USE_GNUTLS*/
1815 if ( write_server (c
->fd
, buffer
, size
) )
1827 /* Close handler for estream. */
1829 cookie_close (void *cookie
)
1831 cookie_t c
= cookie
;
1836 #ifdef HTTP_USE_GNUTLS
1837 if (c
->tls_session
&& !c
->keep_socket
)
1839 gnutls_bye (c
->tls_session
, GNUTLS_SHUT_RDWR
);
1841 #endif /*HTTP_USE_GNUTLS*/
1842 if (c
->fd
!= -1 && !c
->keep_socket
)
1848 #endif /*HTTP_USE_ESTREAM*/
1853 /**** Test code ****/
1857 verify_callback (http_t hd
, void *tls_context
, int reserved
)
1859 log_info ("verification of certificates skipped\n");
1866 /* my_gnutls_log (int level, const char *text) */
1868 /* fprintf (stderr, "gnutls:L%d: %s", level, text); */
1872 main (int argc
, char **argv
)
1879 gnutls_session_t tls_session
= NULL
;
1880 #ifdef HTTP_USE_GNUTLS
1881 gnutls_certificate_credentials certcred
;
1882 const int certprio
[] = { GNUTLS_CRT_X509
, 0 };
1883 #endif /*HTTP_USE_GNUTLS*/
1886 #ifdef HTTP_USE_ESTREAM
1889 log_set_prefix ("http-test", 1 | 4);
1892 /*start_server (); */
1898 fprintf (stderr
, "usage: http-test uri\n");
1904 #ifdef HTTP_USE_GNUTLS
1905 rc
= gnutls_global_init ();
1907 log_error ("gnutls_global_init failed: %s\n", gnutls_strerror (rc
));
1908 rc
= gnutls_certificate_allocate_credentials (&certcred
);
1910 log_error ("gnutls_certificate_allocate_credentials failed: %s\n",
1911 gnutls_strerror (rc
));
1912 /* rc = gnutls_certificate_set_x509_trust_file */
1913 /* (certcred, "ca.pem", GNUTLS_X509_FMT_PEM); */
1915 /* log_error ("gnutls_certificate_set_x509_trust_file failed: %s\n", */
1916 /* gnutls_strerror (rc)); */
1917 rc
= gnutls_init (&tls_session
, GNUTLS_CLIENT
);
1919 log_error ("gnutls_init failed: %s\n", gnutls_strerror (rc
));
1920 rc
= gnutls_set_default_priority (tls_session
);
1922 log_error ("gnutls_set_default_priority failed: %s\n",
1923 gnutls_strerror (rc
));
1924 rc
= gnutls_certificate_type_set_priority (tls_session
, certprio
);
1926 log_error ("gnutls_certificate_type_set_priority failed: %s\n",
1927 gnutls_strerror (rc
));
1928 rc
= gnutls_credentials_set (tls_session
, GNUTLS_CRD_CERTIFICATE
, certcred
);
1930 log_error ("gnutls_credentials_set failed: %s\n", gnutls_strerror (rc
));
1931 /* gnutls_global_set_log_function (my_gnutls_log); */
1932 /* gnutls_global_set_log_level (4); */
1934 http_register_tls_callback (verify_callback
);
1935 #endif /*HTTP_USE_GNUTLS*/
1937 rc
= http_parse_uri (&uri
, *argv
);
1940 log_error ("`%s': %s\n", *argv
, gpg_strerror (rc
));
1941 http_release_parsed_uri (uri
);
1945 printf ("Scheme: %s\n", uri
->scheme
);
1946 printf ("Host : %s\n", uri
->host
);
1947 printf ("Port : %u\n", uri
->port
);
1948 printf ("Path : %s\n", uri
->path
);
1949 for (r
= uri
->params
; r
; r
= r
->next
)
1951 printf ("Params: %s", r
->name
);
1954 printf ("=%s", r
->value
);
1955 if (strlen (r
->value
) != r
->valuelen
)
1956 printf (" [real length=%d]", (int) r
->valuelen
);
1960 for (r
= uri
->query
; r
; r
= r
->next
)
1962 printf ("Query : %s", r
->name
);
1965 printf ("=%s", r
->value
);
1966 if (strlen (r
->value
) != r
->valuelen
)
1967 printf (" [real length=%d]", (int) r
->valuelen
);
1971 http_release_parsed_uri (uri
);
1974 rc
= http_open_document (&hd
, *argv
, NULL
,
1975 HTTP_FLAG_NO_SHUTDOWN
| HTTP_FLAG_NEED_HEADER
,
1979 log_error ("can't get `%s': %s\n", *argv
, gpg_strerror (rc
));
1982 log_info ("open_http_document succeeded; status=%u\n",
1983 http_get_status_code (hd
));
1984 for (hdr
= hd
->headers
; hdr
; hdr
= hdr
->next
)
1985 printf ("HDR: %s: %s\n", hdr
->name
, hdr
->value
);
1986 switch (http_get_status_code (hd
))
1989 while ((c
= P_ES(getc
) (http_get_read_ptr (hd
))) != EOF
)
1994 printf ("Redirected to `%s'\n", http_get_header (hd
, "Location"));
1999 #ifdef HTTP_USE_GNUTLS
2000 gnutls_deinit (tls_session
);
2001 gnutls_certificate_free_credentials (certcred
);
2002 gnutls_global_deinit ();
2003 #endif /*HTTP_USE_GNUTLS*/
2012 compile-command: "gcc -I.. -I../gl -DTEST -DHAVE_CONFIG_H -Wall -O2 -g -o http-test http.c -L. -lcommon -L../jnlib -ljnlib -lgcrypt -lpth -lgnutls"