summaryrefslogtreecommitdiff
path: root/common/http.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/http.c')
-rw-r--r--common/http.c146
1 files changed, 80 insertions, 66 deletions
diff --git a/common/http.c b/common/http.c
index c12bd2b..15d64c4 100644
--- a/common/http.c
+++ b/common/http.c
@@ -1,6 +1,6 @@
/* http.c - HTTP protocol handler
* Copyright (C) 1999, 2001, 2002, 2003, 2004, 2006,
- * 2009 Free Software Foundation, Inc.
+ * 2009, 2012, 2013 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -46,6 +46,9 @@
#include <unistd.h>
#ifdef HAVE_W32_SYSTEM
+# ifdef HAVE_WINSOCK2_H
+# include <winsock2.h>
+# endif
# include <windows.h>
#else /*!HAVE_W32_SYSTEM*/
# include <sys/types.h>
@@ -129,12 +132,12 @@ static int insert_escapes (char *buffer, const char *string,
const char *special);
static uri_tuple_t parse_tuple (char *string);
static gpg_error_t send_request (http_t hd, const char *auth,const char *proxy,
- const char *srvtag,strlist_t headers);
+ struct http_srv *srv,strlist_t headers);
static char *build_rel_path (parsed_uri_t uri);
static gpg_error_t parse_response (http_t hd);
static int connect_server (const char *server, unsigned short port,
- unsigned int flags, const char *srvtag);
+ unsigned int flags, struct http_srv *srv);
static gpg_error_t write_server (int sock, const char *data, size_t length);
#ifdef HTTP_USE_ESTREAM
@@ -150,7 +153,7 @@ static es_cookie_io_functions_t cookie_functions =
cookie_close
};
-struct cookie_s
+struct cookie_s
{
int fd; /* File descriptor or -1 if already closed. */
gnutls_session_t tls_session; /* TLS session context or NULL if not used. */
@@ -176,7 +179,7 @@ typedef struct header_s *header_t;
/* Our handle context. */
-struct http_context_s
+struct http_context_s
{
unsigned int status_code;
int sock;
@@ -228,14 +231,14 @@ init_sockets (void)
if (initialized)
return;
- if ( WSAStartup( MAKEWORD (REQ_WINSOCK_MINOR, REQ_WINSOCK_MAJOR), &wsdata ) )
+ if ( WSAStartup( MAKEWORD (REQ_WINSOCK_MINOR, REQ_WINSOCK_MAJOR), &wsdata ) )
{
- log_error ("error initializing socket library: ec=%d\n",
+ log_error ("error initializing socket library: ec=%d\n",
(int)WSAGetLastError () );
return;
}
- if ( LOBYTE(wsdata.wVersion) != REQ_WINSOCK_MAJOR
- || HIBYTE(wsdata.wVersion) != REQ_WINSOCK_MINOR )
+ if ( LOBYTE(wsdata.wVersion) != REQ_WINSOCK_MAJOR
+ || HIBYTE(wsdata.wVersion) != REQ_WINSOCK_MINOR )
{
log_error ("socket library version is %x.%x - but %d.%d needed\n",
LOBYTE(wsdata.wVersion), HIBYTE(wsdata.wVersion),
@@ -260,7 +263,7 @@ static char *
make_header_line (const char *prefix, const char *suffix,
const void *data, size_t len )
{
- static unsigned char bintoasc[] =
+ static unsigned char bintoasc[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
@@ -278,7 +281,7 @@ make_header_line (const char *prefix, const char *suffix,
*p++ = bintoasc[(((s[1]<<2)&074)|((s[2]>>6)&03))&077];
*p++ = bintoasc[s[2]&077];
}
- if ( len == 2 )
+ if ( len == 2 )
{
*p++ = bintoasc[(s[0] >> 2) & 077];
*p++ = bintoasc[(((s[0] <<4)&060)|((s[1] >> 4)&017))&077];
@@ -306,7 +309,7 @@ http_register_tls_callback ( gpg_error_t (*cb) (http_t, void *, int) )
tls_callback = (gpg_error_t (*) (http_t, gnutls_session_t, int))cb;
#else
(void)cb;
-#endif
+#endif
}
@@ -315,13 +318,13 @@ http_register_tls_callback ( gpg_error_t (*cb) (http_t, void *, int) )
pointer for completing the the request and to wait for the
response. */
gpg_error_t
-http_open (http_t *r_hd, http_req_t reqtype, const char *url,
+http_open (http_t *r_hd, http_req_t reqtype, const char *url,
const char *auth, unsigned int flags, const char *proxy,
- void *tls_context, const char *srvtag,strlist_t headers)
+ void *tls_context, struct http_srv *srv, strlist_t headers)
{
gpg_error_t err;
http_t hd;
-
+
*r_hd = NULL;
if (!(reqtype == HTTP_REQ_GET || reqtype == HTTP_REQ_POST))
@@ -338,8 +341,8 @@ http_open (http_t *r_hd, http_req_t reqtype, const char *url,
err = http_parse_uri (&hd->uri, url);
if (!err)
- err = send_request (hd, auth, proxy, srvtag, headers);
-
+ err = send_request (hd, auth, proxy, srv, headers);
+
if (err)
{
if (!hd->fp_read && !hd->fp_write && hd->sock != -1)
@@ -382,7 +385,7 @@ http_wait_response (http_t hd)
gpg_error_t err;
/* Make sure that we are in the data. */
- http_start_data (hd);
+ http_start_data (hd);
/* We dup the socket, to cope with the fact that fclose closes the
underlying socket. In TLS mode we don't do that because we can't
@@ -417,8 +420,6 @@ http_wait_response (http_t hd)
hd->write_cookie = NULL;
#endif
- if (!(hd->flags & HTTP_FLAG_NO_SHUTDOWN))
- shutdown (hd->sock, 1);
hd->in_data = 0;
#ifdef HTTP_USE_ESTREAM
@@ -455,14 +456,15 @@ http_wait_response (http_t hd)
be used as an HTTP proxy and any enabled $http_proxy gets
ignored. */
gpg_error_t
-http_open_document (http_t *r_hd, const char *document,
+http_open_document (http_t *r_hd, const char *document,
const char *auth, unsigned int flags, const char *proxy,
- void *tls_context, const char *srvtag,strlist_t headers)
+ void *tls_context, struct http_srv *srv,
+ strlist_t headers)
{
gpg_error_t err;
err = http_open (r_hd, HTTP_REQ_GET, document, auth, flags,
- proxy, tls_context, srvtag, headers);
+ proxy, tls_context, srv, headers);
if (err)
return err;
@@ -608,7 +610,7 @@ do_parse_uri (parsed_uri_t uri, int only_local_part)
p++;
if (*p == '/') /* There seems to be a hostname. */
- {
+ {
p++;
if ((p2 = strchr (p, '/')))
*p2++ = 0;
@@ -666,7 +668,7 @@ do_parse_uri (parsed_uri_t uri, int only_local_part)
return gpg_error (GPG_ERR_BAD_URI); /* Path includes a Nul. */
p = p2 ? p2 : NULL;
- if (!p || !*p)
+ if (!p || !*p)
return 0; /* We don't have a query string. Okay. */
/* Now parse the query string. */
@@ -836,7 +838,7 @@ parse_tuple (char *string)
*/
static gpg_error_t
send_request (http_t hd, const char *auth,
- const char *proxy,const char *srvtag,strlist_t headers)
+ const char *proxy, struct http_srv *srv, strlist_t headers)
{
gnutls_session_t tls_session;
gpg_error_t err;
@@ -860,7 +862,7 @@ send_request (http_t hd, const char *auth,
if ( (proxy && *proxy)
|| ( (hd->flags & HTTP_FLAG_TRY_PROXY)
- && (http_proxy = getenv (HTTP_PROXY_ENV))
+ && (http_proxy = getenv (HTTP_PROXY_ENV))
&& *http_proxy ))
{
parsed_uri_t uri;
@@ -894,20 +896,20 @@ send_request (http_t hd, const char *auth,
hd->sock = connect_server (*uri->host ? uri->host : "localhost",
uri->port ? uri->port : 80,
- hd->flags, srvtag);
+ hd->flags, srv);
save_errno = errno;
http_release_parsed_uri (uri);
}
else
{
- hd->sock = connect_server (server, port, hd->flags, srvtag);
+ hd->sock = connect_server (server, port, hd->flags, srv);
save_errno = errno;
}
if (hd->sock == -1)
{
xfree (proxy_authstr);
- return (save_errno
+ return (save_errno
? gpg_error_from_errno (save_errno)
: gpg_error (GPG_ERR_NOT_FOUND));
}
@@ -947,7 +949,7 @@ send_request (http_t hd, const char *auth,
if (auth || hd->uri->auth)
{
char *myauth;
-
+
if (auth)
{
myauth = xtrystrdup (auth);
@@ -975,12 +977,12 @@ send_request (http_t hd, const char *auth,
return gpg_error_from_syserror ();
}
}
-
+
p = build_rel_path (hd->uri);
if (!p)
return gpg_error_from_syserror ();
- request = xtrymalloc (2 * strlen (server)
+ request = xtrymalloc (2 * strlen (server)
+ strlen (p)
+ (authstr?strlen(authstr):0)
+ (proxy_authstr?strlen(proxy_authstr):0)
@@ -1007,8 +1009,8 @@ send_request (http_t hd, const char *auth,
else
{
char portstr[35];
-
- if (port == 80)
+
+ if (port == 80 || (srv && srv->used_server))
*portstr = 0;
else
sprintf (portstr, ":%u", port);
@@ -1189,7 +1191,7 @@ my_read_line (
char *p;
if (!buffer) /* Must allocate a new buffer. */
- {
+ {
length = 256;
buffer = xtrymalloc (length);
*addr_of_buffer = buffer;
@@ -1206,7 +1208,7 @@ my_read_line (
while ((c = P_ES(getc) (fp)) != EOF)
{
if (nbytes == length) /* Increase the buffer. */
- {
+ {
if (length > maxlen) /* Limit reached. */
{
/* Skip the rest of the line. */
@@ -1311,7 +1313,7 @@ store_header (http_t hd, char *line)
while (*p == ' ' || *p == '\t')
p++;
value = p;
-
+
for (h=hd->headers; h; h = h->next)
if ( !strcmp (h->name, line) )
break;
@@ -1540,12 +1542,14 @@ start_server ()
error. ERRNO is set on error. */
static int
connect_server (const char *server, unsigned short port,
- unsigned int flags, const char *srvtag)
+ unsigned int flags, struct http_srv *srv)
{
int sock = -1;
int srvcount = 0;
+ int fakesrv = 0;
int hostfound = 0;
- int srv, connected;
+ int srvindex, connected;
+ int chosen = -1;
int last_errno = 0;
struct srventry *serverlist = NULL;
@@ -1564,9 +1568,9 @@ connect_server (const char *server, unsigned short port,
if ( inaddr != INADDR_NONE )
{
struct sockaddr_in addr;
-
+
memset(&addr,0,sizeof(addr));
-
+
sock = socket(AF_INET,SOCK_STREAM,0);
if ( sock==INVALID_SOCKET )
{
@@ -1574,9 +1578,9 @@ connect_server (const char *server, unsigned short port,
return -1;
}
- addr.sin_family = AF_INET;
+ addr.sin_family = AF_INET;
addr.sin_port = htons(port);
- memcpy (&addr.sin_addr,&inaddr,sizeof(inaddr));
+ memcpy (&addr.sin_addr,&inaddr,sizeof(inaddr));
if (!connect (sock,(struct sockaddr *)&addr,sizeof(addr)) )
return sock;
@@ -1587,14 +1591,14 @@ connect_server (const char *server, unsigned short port,
#ifdef USE_DNS_SRV
/* Do the SRV thing */
- if (srvtag)
+ if (srv && srv->srvtag)
{
/* We're using SRV, so append the tags. */
- if (1+strlen (srvtag) + 6 + strlen (server) + 1 <= MAXDNAME)
+ if (1+strlen (srv->srvtag) + 6 + strlen (server) + 1 <= MAXDNAME)
{
char srvname[MAXDNAME];
- stpcpy (stpcpy (stpcpy (stpcpy (srvname,"_"), srvtag),
+ stpcpy (stpcpy (stpcpy (stpcpy (srvname,"_"), srv->srvtag),
"._tcp."), server);
srvcount = getsrv (srvname, &serverlist);
}
@@ -1612,19 +1616,20 @@ connect_server (const char *server, unsigned short port,
strncpy (serverlist->target, server, MAXDNAME);
serverlist->target[MAXDNAME-1] = '\0';
srvcount = 1;
+ fakesrv = 1;
}
#ifdef HAVE_GETADDRINFO
connected = 0;
- for (srv=0; srv < srvcount && !connected; srv++)
+ for (srvindex=0; srvindex < srvcount && !connected; srvindex++)
{
struct addrinfo hints, *res, *ai;
char portstr[35];
- sprintf (portstr, "%hu", port);
+ sprintf (portstr, "%hu", serverlist[srvindex].port);
memset (&hints, 0, sizeof (hints));
hints.ai_socktype = SOCK_STREAM;
- if (getaddrinfo (serverlist[srv].target, portstr, &hints, &res))
+ if (getaddrinfo (serverlist[srvindex].target, portstr, &hints, &res))
continue; /* Not found - try next one. */
hostfound = 1;
@@ -1642,17 +1647,20 @@ connect_server (const char *server, unsigned short port,
errno = save_errno;
return -1;
}
-
+
if (connect (sock, ai->ai_addr, ai->ai_addrlen))
last_errno = errno;
else
- connected = 1;
+ {
+ connected = 1;
+ chosen = srvindex;
+ }
}
freeaddrinfo (res);
}
#else /* !HAVE_GETADDRINFO */
connected = 0;
- for (srv=0; srv < srvcount && !connected; srv++)
+ for (srvindex=0; srvindex < srvcount && !connected; srvindex++)
{
int i;
struct hostent *host = NULL;
@@ -1661,7 +1669,7 @@ connect_server (const char *server, unsigned short port,
/* Note: This code is not thread-safe. */
memset (&addr, 0, sizeof (addr));
- host = gethostbyname (serverlist[srv].target);
+ host = gethostbyname (serverlist[srvindex].target);
if (!host)
continue;
hostfound = 1;
@@ -1675,20 +1683,20 @@ connect_server (const char *server, unsigned short port,
xfree (serverlist);
return -1;
}
-
+
addr.sin_family = host->h_addrtype;
if (addr.sin_family != AF_INET)
{
log_error ("unknown address family for `%s'\n",
- serverlist[srv].target);
+ serverlist[srvindex].target);
xfree (serverlist);
return -1;
}
- addr.sin_port = htons (serverlist[srv].port);
+ addr.sin_port = htons (serverlist[srvindex].port);
if (host->h_length != 4)
{
log_error ("illegal address length for `%s'\n",
- serverlist[srv].target);
+ serverlist[srvindex].target);
xfree (serverlist);
return -1;
}
@@ -1702,12 +1710,19 @@ connect_server (const char *server, unsigned short port,
else
{
connected = 1;
+ chosen = srvindex;
break;
}
}
}
#endif /* !HAVE_GETADDRINFO */
+ if(!fakesrv && chosen >- 1 && srv)
+ {
+ srv->used_server = xstrdup (serverlist[chosen].target);
+ srv->used_port = serverlist[chosen].port;
+ }
+
xfree (serverlist);
if (!connected)
@@ -1741,9 +1756,9 @@ write_server (int sock, const char *data, size_t length)
{
#ifdef HAVE_W32_SYSTEM
int nwritten;
-
+
nwritten = send (sock, data, nleft, 0);
- if ( nwritten == SOCKET_ERROR )
+ if ( nwritten == SOCKET_ERROR )
{
log_info ("network write failed: ec=%d\n", (int)WSAGetLastError ());
return gpg_error (GPG_ERR_NETWORK);
@@ -1796,7 +1811,7 @@ cookie_read (void *cookie, void *buffer, size_t size)
if (nread == GNUTLS_E_AGAIN)
{
struct timeval tv;
-
+
tv.tv_sec = 0;
tv.tv_usec = 50000;
select (0, NULL, NULL, NULL, &tv);
@@ -1817,7 +1832,7 @@ cookie_read (void *cookie, void *buffer, size_t size)
#ifdef HAVE_W32_SYSTEM
/* Under Windows we need to use recv for a socket. */
nread = recv (c->fd, buffer, size, 0);
-#else
+#else
nread = read (c->fd, buffer, size);
#endif
}
@@ -1840,7 +1855,7 @@ cookie_write (void *cookie, const void *buffer, size_t size)
int nleft = size;
while (nleft > 0)
{
- nwritten = gnutls_record_send (c->tls_session, buffer, nleft);
+ nwritten = gnutls_record_send (c->tls_session, buffer, nleft);
if (nwritten <= 0)
{
if (nwritten == GNUTLS_E_INTERRUPTED)
@@ -1848,7 +1863,7 @@ cookie_write (void *cookie, const void *buffer, size_t size)
if (nwritten == GNUTLS_E_AGAIN)
{
struct timeval tv;
-
+
tv.tv_sec = 0;
tv.tv_usec = 50000;
select (0, NULL, NULL, NULL, &tv);
@@ -2025,8 +2040,7 @@ main (int argc, char **argv)
http_release_parsed_uri (uri);
uri = NULL;
- rc = http_open_document (&hd, *argv, NULL,
- HTTP_FLAG_NO_SHUTDOWN | HTTP_FLAG_NEED_HEADER,
+ rc = http_open_document (&hd, *argv, NULL, HTTP_FLAG_NEED_HEADER,
NULL, tls_session);
if (rc)
{