From 43e8714797d40bcf63efab428dcd25f9caf1d52b Mon Sep 17 00:00:00 2001 From: Jakub Sławiński Date: Fri, 5 Aug 2005 21:45:31 +0200 Subject: v0.7.2 - Added: http proxy basic authorization - Fixed: logging initialization after some value checking - Fixed: auto-reconnect failure when --nossl option is set - Added: auto-reconnect when afserver is not reachable on start - Added: auto-reconnect after normal afserver quit - Added: per user statistics: idle time, amount of downloaded/uploaded bytes and current download/upload rate - Added: support for https proxies - Added: possibility to bind sockets on different interfaces - Fixed: receiving incomplete headers from afclient - Fixed: close user connections by afclient --- src/http_proxy_client.c | 366 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 272 insertions(+), 94 deletions(-) (limited to 'src/http_proxy_client.c') diff --git a/src/http_proxy_client.c b/src/http_proxy_client.c index 2cd301a..9f0cc7c 100644 --- a/src/http_proxy_client.c +++ b/src/http_proxy_client.c @@ -26,15 +26,16 @@ #include "network.h" #include "stats.h" #include "logging.h" +#include "base64.h" #ifdef HAVE_LIBPTHREAD typedef struct { int sockfd; char *host; char *serv; - char *proxyname; - char *proxyport; + HttpProxyOptions* hpo; char type; + SSL_CTX* ctx; } proxy_argT; static void @@ -57,8 +58,10 @@ http_proxy_client(void *vptr) struct timeval tv; int timeout = 5; int tmp; - char *host, *serv, *proxyname, *proxyport; - char type; + char *host, *serv, *proxyname, *proxyport, *credentials, *name = ""; + char b64cred[100]; + char type, authtype, https; + SSL_CTX* ctx; proxy_argT *proxy_argptr; start_critical_section(); @@ -66,14 +69,60 @@ http_proxy_client(void *vptr) host = proxy_argptr->host; serv = proxy_argptr->serv; - proxyname = proxy_argptr->proxyname; - proxyport = proxy_argptr->proxyport; + proxyname = HttpProxyOptions_get_proxyname(proxy_argptr->hpo); + proxyport = HttpProxyOptions_get_proxyport(proxy_argptr->hpo); + credentials = HttpProxyOptions_get_proxyauth_cred(proxy_argptr->hpo); type = proxy_argptr->type; + authtype = HttpProxyOptions_get_proxyauth_type(proxy_argptr->hpo); conn.sockfd = proxy_argptr->sockfd; + https = HttpProxyOptions_is_https(proxy_argptr->hpo); + ctx = proxy_argptr->ctx; broadcast_condition(); end_critical_section(); + conn.postFd = SslFd_new(); + conn.getFd = SslFd_new(); + conn.tmpFd = SslFd_new(); + if ((conn.postFd == NULL) || (conn.getFd == NULL) || (conn.tmpFd == NULL)) { + aflog(LOG_T_INIT, LOG_I_CRIT, + "http%s proxy: Can't allocate memory... exiting.", name); + exit(1); + } + + if (https) { + name = "s"; + SslFd_set_ssl(conn.postFd, SSL_new(ctx)); + SslFd_set_ssl(conn.getFd, SSL_new(ctx)); + SslFd_set_ssl(conn.tmpFd, SSL_new(ctx)); + if ((SslFd_get_ssl(conn.postFd) == NULL) || + (SslFd_get_ssl(conn.getFd) == NULL) || + (SslFd_get_ssl(conn.tmpFd) == NULL)) { + aflog(LOG_T_INIT, LOG_I_CRIT, + "http%s proxy: Can't allocate memory... exiting.", name); + exit(1); + } + } + + if (authtype == PROXYAUTH_TYPE_WRONG) { + aflog(LOG_T_MAIN, LOG_I_WARNING, + "Wrong type of proxy authorizaton --> switching to no authorization"); + credentials = NULL; + } + + if (credentials) { + if (b64_ntop((unsigned char*)credentials, strlen(credentials), b64cred, 100) == -1) { + aflog(LOG_T_MAIN, LOG_I_ERR, + "Cannot encode credentials for proxy authorization"); + b64cred[0] = 0; + } + else { + if (authtype == PROXYAUTH_TYPE_NOTSET) { + authtype = PROXYAUTH_TYPE_BASIC; + } + } + } + FD_ZERO(&allset); tv.tv_usec = 0; tv.tv_sec = timeout; @@ -86,65 +135,111 @@ http_proxy_client(void *vptr) /* postfd */ aflog(LOG_T_MAIN, LOG_I_DEBUG, - "http proxy: connecting (postfd)..."); - if (ip_connect(&conn.postfd, proxyname, proxyport, type)) { + "http%s proxy: connecting (postfd)...", name); + if (ip_connect(&tmp, proxyname, proxyport, type)) { clean_return(conn.sockfd); } - + SslFd_set_fd(conn.postFd, tmp); + if (https) { + if (SSL_set_fd(SslFd_get_ssl(conn.postFd), SslFd_get_fd(conn.postFd)) != 1) { + aflog(LOG_T_INIT, LOG_I_CRIT, + "https proxy: Problem with initializing ssl"); + clean_return(conn.sockfd); + } + if (SSL_connect(SslFd_get_ssl(conn.postFd)) != 1) { + aflog(LOG_T_INIT, LOG_I_CRIT, + "https proxy: SSL_connect has failed"); + clean_return(conn.sockfd); + } + } memset(tab, 0, 9000); - sprintf(tab, - "POST http://%s:%s/yahpt.html?id=%s HTTP/1.1\r\n" - "Host: %s:%s\r\n" - "Content-Length: 90000\r\n" - "Connection: close\r\n\r\n", host, serv, conn.id, host, serv); + switch (authtype) { + case PROXYAUTH_TYPE_BASIC: + sprintf(tab, + "POST http://%s:%s/yahpt.html?id=%s HTTP/1.1\r\n" + "Host: %s:%s\r\n" + "Content-Length: 90000\r\n" + "Connection: close\r\n" + "Proxy-Authorization: Basic %s\r\n\r\n", host, serv, conn.id, host, serv, b64cred); + break; + default: + sprintf(tab, + "POST http://%s:%s/yahpt.html?id=%s HTTP/1.1\r\n" + "Host: %s:%s\r\n" + "Content-Length: 90000\r\n" + "Connection: close\r\n\r\n", host, serv, conn.id, host, serv); + } j = strlen (tab); aflog(LOG_T_MAIN, LOG_I_DEBUG, - "http proxy: writing POST request..."); - if (writen(conn.postfd, (unsigned char*) tab, j) <= 0) { + "http%s proxy: writing POST request...", name); + if (http_write(https, conn.postFd, (unsigned char*) tab, j) <= 0) { clean_return(conn.sockfd); } /* getfd */ aflog(LOG_T_MAIN, LOG_I_DEBUG, - "http proxy: connecting (getfd)..."); - if (ip_connect(&conn.getfd, proxyname, proxyport, type)) { + "http%s proxy: connecting (getfd)...", name); + if (ip_connect(&tmp, proxyname, proxyport, type)) { clean_return(conn.sockfd); } + SslFd_set_fd(conn.getFd, tmp); + if (https) { + if (SSL_set_fd(SslFd_get_ssl(conn.getFd), SslFd_get_fd(conn.getFd)) != 1) { + aflog(LOG_T_INIT, LOG_I_CRIT, + "https proxy: Problem with initializing ssl"); + clean_return(conn.sockfd); + } + if (SSL_connect(SslFd_get_ssl(conn.getFd)) != 1) { + aflog(LOG_T_INIT, LOG_I_CRIT, + "https proxy: SSL_connect has failed"); + clean_return(conn.sockfd); + } + } memset(tab, 0, 9000); - sprintf(tab, - "GET http://%s:%s/yahpt.html?id=%s HTTP/1.1\r\n" - "Host: %s:%s\r\n" - "Connection: close\r\n\r\n", host, serv, conn.id, host, serv); + switch (authtype) { + case PROXYAUTH_TYPE_BASIC: + sprintf(tab, + "GET http://%s:%s/yahpt.html?id=%s HTTP/1.1\r\n" + "Host: %s:%s\r\n" + "Connection: close\r\n" + "Proxy-Authorization: Basic %s\r\n\r\n", host, serv, conn.id, host, serv, b64cred); + break; + default: + sprintf(tab, + "GET http://%s:%s/yahpt.html?id=%s HTTP/1.1\r\n" + "Host: %s:%s\r\n" + "Connection: close\r\n\r\n", host, serv, conn.id, host, serv); + } j = strlen (tab); aflog(LOG_T_MAIN, LOG_I_DEBUG, - "http proxy: writing GET request..."); - if (writen(conn.getfd, (unsigned char*) tab, j) <= 0) { + "http%s proxy: writing GET request...", name); + if (http_write(https, conn.getFd, (unsigned char*) tab, j) <= 0) { clean_return(conn.sockfd); } set_fd(conn.sockfd, &maxfdp1, &allset); - set_fd(conn.postfd, &maxfdp1, &allset); - set_fd(conn.getfd, &maxfdp1, &allset); + set_fd(SslFd_get_fd(conn.postFd), &maxfdp1, &allset); + set_fd(SslFd_get_fd(conn.getFd), &maxfdp1, &allset); conn.state = C_OPEN; memset(tab, 0, 9000); aflog(LOG_T_MAIN, LOG_I_DEBUG, - "http proxy: parsing header from getfd"); - if (parse_header(conn.getfd, tab, &hdr)) { + "http%s proxy: parsing header from getfd", name); + if (parse_header(conn.getFd, tab, &hdr, https)) { clean_return(conn.sockfd); } aflog(LOG_T_MAIN, LOG_I_DEBUG, - "http proxy: checking hdr.type"); + "http%s proxy: checking hdr.type", name); if (hdr.type != H_TYPE_OK) { clean_return(conn.sockfd); } if (hdr.length) { conn.received += hdr.length; aflog(LOG_T_MAIN, LOG_I_DEBUG, - "http proxy: reading message..."); + "http%s proxy: reading message...", name); if (read_message(conn.sockfd, hdr.length, &conn, tab, hdr.ptr)) { clean_return(conn.sockfd); } @@ -155,46 +250,70 @@ http_proxy_client(void *vptr) if (select(maxfdp1, &rset, NULL, NULL, &tv) == 0) { aflog(LOG_T_MAIN, LOG_I_DDEBUG, - "http proxy: timeout"); + "http%s proxy: timeout", name); tv.tv_sec = timeout; if (conn.state == C_CLOSED) { continue; } if (conn.sent_ptr+1 >= 90000) { aflog(LOG_T_MAIN, LOG_I_DDEBUG, - "http proxy: send T"); - writen(conn.postfd, (unsigned char*) "T", 1); + "http%s proxy: send T", name); + http_write(https, conn.postFd, (unsigned char*) "T", 1); conn.sent_ptr = 0; - clear_fd(&conn.postfd, &allset); + clear_sslFd(conn.postFd, &allset); /* postfd */ aflog(LOG_T_MAIN, LOG_I_DEBUG, - "http proxy: connecting (postfd)..."); - if (ip_connect(&conn.postfd, proxyname, proxyport, type)) { + "http%s proxy: connecting (postfd)...", name); + if (ip_connect(&tmp, proxyname, proxyport, type)) { clean_return(conn.sockfd); } - + SslFd_set_fd(conn.postFd, tmp); + if (https) { + if (SSL_set_fd(SslFd_get_ssl(conn.postFd), SslFd_get_fd(conn.postFd)) != 1) { + aflog(LOG_T_INIT, LOG_I_CRIT, + "https proxy: Problem with initializing ssl"); + clean_return(conn.sockfd); + } + if (SSL_connect(SslFd_get_ssl(conn.postFd)) != 1) { + aflog(LOG_T_INIT, LOG_I_CRIT, + "https proxy: SSL_connect has failed"); + clean_return(conn.sockfd); + } + } + memset(tab, 0, 9000); - sprintf(tab, - "POST http://%s:%s/yahpt.html?id=%s HTTP/1.1\r\n" - "Host: %s:%s\r\n" - "Content-Length: 90000\r\n" - "Connection: close\r\n\r\n", host, serv, conn.id, host, serv); + switch (authtype) { + case PROXYAUTH_TYPE_BASIC: + sprintf(tab, + "POST http://%s:%s/yahpt.html?id=%s HTTP/1.1\r\n" + "Host: %s:%s\r\n" + "Content-Length: 90000\r\n" + "Connection: close\r\n" + "Proxy-Authorization: Basic %s\r\n\r\n", host, serv, conn.id, host, serv, b64cred); + break; + default: + sprintf(tab, + "POST http://%s:%s/yahpt.html?id=%s HTTP/1.1\r\n" + "Host: %s:%s\r\n" + "Content-Length: 90000\r\n" + "Connection: close\r\n\r\n", host, serv, conn.id, host, serv); + } j = strlen (tab); aflog(LOG_T_MAIN, LOG_I_DEBUG, - "http proxy: writing POST request..."); - if (writen(conn.postfd, (unsigned char *) tab, j) <= 0) { + "http%s proxy: writing POST request...", name); + if (http_write(https, conn.postFd, (unsigned char *) tab, j) <= 0) { clean_return(conn.sockfd); } conn.sent_ptr = 0; conn.ptr = 0; conn.length = 0; - set_fd(conn.postfd, &maxfdp1, &allset); + set_fd(SslFd_get_fd(conn.postFd), &maxfdp1, &allset); } else { aflog(LOG_T_MAIN, LOG_I_DDEBUG, - "http proxy: send T"); - writen(conn.postfd, (unsigned char *) "T", 1); + "http%s proxy: send T", name); + http_write(https, conn.postFd, (unsigned char *) "T", 1); conn.sent_ptr += 1; } continue; @@ -203,21 +322,34 @@ http_proxy_client(void *vptr) /* sockfd */ if (FD_ISSET(conn.sockfd, &rset)) { aflog(LOG_T_MAIN, LOG_I_DDEBUG, - "http proxy: FD_ISSET(conn.sockfd)"); + "http%s proxy: FD_ISSET(conn.sockfd)", name); if (conn.state == C_CLOSED) { /* postfd */ aflog(LOG_T_MAIN, LOG_I_DEBUG, - "http proxy: connecting (postfd)..."); - if (ip_connect(&conn.postfd, proxyname, proxyport, type)) { + "http%s proxy: connecting (postfd)...", name); + if (ip_connect(&tmp, proxyname, proxyport, type)) { clean_return(conn.sockfd); } + SslFd_set_fd(conn.postFd, tmp); + if (https) { + if (SSL_set_fd(SslFd_get_ssl(conn.postFd), SslFd_get_fd(conn.postFd)) != 1) { + aflog(LOG_T_INIT, LOG_I_CRIT, + "https proxy: Problem with initializing ssl"); + clean_return(conn.sockfd); + } + if (SSL_connect(SslFd_get_ssl(conn.postFd)) != 1) { + aflog(LOG_T_INIT, LOG_I_CRIT, + "https proxy: SSL_connect has failed"); + clean_return(conn.sockfd); + } + } conn.state = C_OPEN; } n = read(conn.sockfd, conn.buf+5, 8995); if (n <= 0) { aflog(LOG_T_MAIN, LOG_I_DEBUG, - "http proxy: send Q"); - writen(conn.postfd, (unsigned char *) "Q", 1); + "http%s proxy: send Q", name); + http_write(https, conn.postFd, (unsigned char *) "Q", 1); clean_return(conn.sockfd); } conn.buf[0] = 'M'; @@ -225,36 +357,60 @@ http_proxy_client(void *vptr) memcpy(&conn.buf[1], &tmp, 4); if (conn.sent_ptr+5 + n >= 90000) { aflog(LOG_T_MAIN, LOG_I_DEBUG, - "http proxy: send message"); - writen(conn.postfd, (unsigned char *) conn.buf, 90000 - conn.sent_ptr); + "http%s proxy: send message", name); + http_write(https, conn.postFd, (unsigned char *) conn.buf, 90000 - conn.sent_ptr); conn.ptr = 90000 - conn.sent_ptr; conn.length = 5+n - conn.ptr; conn.sent_ptr = 0; - clear_fd(&conn.postfd, &allset); + clear_sslFd(conn.postFd, &allset); /* postfd */ aflog(LOG_T_MAIN, LOG_I_DEBUG, - "http proxy: connecting (postfd)..."); - if (ip_connect(&conn.postfd, proxyname, proxyport, type)) { + "http%s proxy: connecting (postfd)...", name); + if (ip_connect(&tmp, proxyname, proxyport, type)) { clean_return(conn.sockfd); } + SslFd_set_fd(conn.postFd, tmp); + if (https) { + if (SSL_set_fd(SslFd_get_ssl(conn.postFd), SslFd_get_fd(conn.postFd)) != 1) { + aflog(LOG_T_INIT, LOG_I_CRIT, + "https proxy: Problem with initializing ssl"); + clean_return(conn.sockfd); + } + if (SSL_connect(SslFd_get_ssl(conn.postFd)) != 1) { + aflog(LOG_T_INIT, LOG_I_CRIT, + "https proxy: SSL_connect has failed"); + clean_return(conn.sockfd); + } + } memset(tab, 0, 9000); - sprintf(tab, - "POST http://%s:%s/yahpt.html?id=%s HTTP/1.1\r\n" - "Host: %s:%s\r\n" - "Content-Length: 90000\r\n" - "Connection: close\r\n\r\n", host, serv, conn.id, host, serv); + switch (authtype) { + case PROXYAUTH_TYPE_BASIC: + sprintf(tab, + "POST http://%s:%s/yahpt.html?id=%s HTTP/1.1\r\n" + "Host: %s:%s\r\n" + "Content-Length: 90000\r\n" + "Connection: close\r\n" + "Proxy-Authorization: Basic %s\r\n\r\n", host, serv, conn.id, host, serv, b64cred); + break; + default: + sprintf(tab, + "POST http://%s:%s/yahpt.html?id=%s HTTP/1.1\r\n" + "Host: %s:%s\r\n" + "Content-Length: 90000\r\n" + "Connection: close\r\n\r\n", host, serv, conn.id, host, serv); + } j = strlen (tab); aflog(LOG_T_MAIN, LOG_I_DEBUG, - "http proxy: writing POST request..."); - if (writen(conn.postfd, (unsigned char *) tab, j) <= 0) { + "http%s proxy: writing POST request...", name); + if (http_write(https, conn.postFd, (unsigned char *) tab, j) <= 0) { clean_return(conn.sockfd); } if (conn.length > 0) { aflog(LOG_T_MAIN, LOG_I_DEBUG, - "http proxy: writing old data..."); - if (writen(conn.postfd, (unsigned char *) (conn.buf+conn.ptr), conn.length) <= 0) { + "http%s proxy: writing old data...", name); + if (http_write(https, conn.postFd, (unsigned char *) (conn.buf+conn.ptr), conn.length) <= 0) { clean_return(conn.sockfd); } } @@ -262,62 +418,84 @@ http_proxy_client(void *vptr) conn.ptr = 0; conn.length = 0; - set_fd(conn.postfd, &maxfdp1, &allset); + set_fd(SslFd_get_fd(conn.postFd), &maxfdp1, &allset); } else { aflog(LOG_T_MAIN, LOG_I_DEBUG, - "http proxy: send message"); - writen(conn.postfd, (unsigned char *) conn.buf, 5+n); + "http%s proxy: send message", name); + http_write(https, conn.postFd, (unsigned char *) conn.buf, 5+n); conn.sent_ptr += 5+n; } } /* getfd */ - if (FD_ISSET(conn.getfd, &rset)) { + if (FD_ISSET(SslFd_get_fd(conn.getFd), &rset)) { aflog(LOG_T_MAIN, LOG_I_DDEBUG, - "http proxy: FD_ISSET(conn.getfd)"); - n = read(conn.getfd, tab, 9000); + "http%s proxy: FD_ISSET(conn.getfd)", name); + n = http_read(https, conn.getFd, (unsigned char*) tab, 9000); conn.received += n; if (n == 0) { conn.received = 0; - FD_CLR(conn.getfd, &allset); - close(conn.getfd); + clear_sslFd(conn.getFd, &allset); /* getfd */ aflog(LOG_T_MAIN, LOG_I_DEBUG, - "http proxy: connecting (getfd)..."); - if (ip_connect(&conn.getfd, proxyname, proxyport, type)) { + "http%s proxy: connecting (getfd)...", name); + if (ip_connect(&tmp, proxyname, proxyport, type)) { clean_return(conn.sockfd); } + SslFd_set_fd(conn.getFd, tmp); + if (https) { + if (SSL_set_fd(SslFd_get_ssl(conn.getFd), SslFd_get_fd(conn.getFd)) != 1) { + aflog(LOG_T_INIT, LOG_I_CRIT, + "https proxy: Problem with initializing ssl"); + clean_return(conn.sockfd); + } + if (SSL_connect(SslFd_get_ssl(conn.getFd)) != 1) { + aflog(LOG_T_INIT, LOG_I_CRIT, + "https proxy: SSL_connect has failed"); + clean_return(conn.sockfd); + } + } memset(tab, 0, 9000); - sprintf(tab, - "GET http://%s:%s/yahpt.html?id=%s HTTP/1.1\r\n" - "Host: %s:%s\r\n" - "Connection: close\r\n\r\n", host, serv, conn.id, host, serv); + switch (authtype) { + case PROXYAUTH_TYPE_BASIC: + sprintf(tab, + "GET http://%s:%s/yahpt.html?id=%s HTTP/1.1\r\n" + "Host: %s:%s\r\n" + "Connection: close\r\n" + "Proxy-Authorization: Basic %s\r\n\r\n", host, serv, conn.id, host, serv, b64cred); + break; + default: + sprintf(tab, + "GET http://%s:%s/yahpt.html?id=%s HTTP/1.1\r\n" + "Host: %s:%s\r\n" + "Connection: close\r\n\r\n", host, serv, conn.id, host, serv); + } j = strlen (tab); aflog(LOG_T_MAIN, LOG_I_DEBUG, - "http proxy: writing GET request..."); - if (writen(conn.getfd, (unsigned char *) tab, j) <= 0) { + "http%s proxy: writing GET request...", name); + if (http_write(https, conn.getFd, (unsigned char *) tab, j) <= 0) { clean_return(conn.sockfd); } memset(tab, 0, 9000); aflog(LOG_T_MAIN, LOG_I_DEBUG, - "http proxy: parsing header from getfd"); - if (parse_header(conn.getfd, tab, &hdr)) { + "http%s proxy: parsing header from getfd", name); + if (parse_header(conn.getFd, tab, &hdr, https)) { clean_return(conn.sockfd); } aflog(LOG_T_MAIN, LOG_I_DEBUG, - "http proxy: checking hdr.type"); + "http%s proxy: checking hdr.type", name); if (hdr.type != H_TYPE_OK) { clean_return(conn.sockfd); } - set_fd(conn.getfd, &maxfdp1, &allset); + set_fd(SslFd_get_fd(conn.getFd), &maxfdp1, &allset); if (hdr.length) { conn.received += hdr.length; aflog(LOG_T_MAIN, LOG_I_DEBUG, - "http proxy: reading message..."); + "http%s proxy: reading message...", name); if (read_message(conn.sockfd, hdr.length, &conn, tab, hdr.ptr)) { clean_return(conn.sockfd); } @@ -331,10 +509,10 @@ http_proxy_client(void *vptr) } /* postfd */ - if (FD_ISSET(conn.postfd, &rset)) { + if (FD_ISSET(SslFd_get_fd(conn.postFd), &rset)) { aflog(LOG_T_MAIN, LOG_I_DDEBUG, - "http proxy: FD_ISSET(conn.postfd)"); - clear_fd(&conn.postfd, &allset); + "http%s proxy: FD_ISSET(conn.postfd)", name); + clear_sslFd(conn.postFd, &allset); conn.state = C_CLOSED; } } @@ -343,7 +521,7 @@ http_proxy_client(void *vptr) int initialize_http_proxy_client(int* sockfd, const char *host, const char *serv, - const char *proxyname, const char *proxyport, const char type) + HttpProxyOptions* hpo, const char type, SSL_CTX* ctx) { int retval; int sockets[2]; @@ -355,7 +533,7 @@ initialize_http_proxy_client(int* sockfd, const char *host, const char *serv, } (*sockfd) = sockets[0]; - if (proxyname == NULL) { + if (HttpProxyOptions_get_proxyname(hpo) == NULL) { return 1; } @@ -363,10 +541,10 @@ initialize_http_proxy_client(int* sockfd, const char *host, const char *serv, arg.host = (char*) host; arg.serv = (char*) serv; - arg.proxyname = (char*) proxyname; - arg.proxyport = (char*) proxyport; + arg.hpo = hpo; arg.type = (char) type; arg.sockfd = sockets[1]; + arg.ctx = ctx; retval = pthread_create(&proxy_thread, NULL, &http_proxy_client, &arg); -- cgit v1.1