Mercurial > dovecot > core-2.2
changeset 19039:8f8f768937f5
http-client: Added support for using an HTTP proxy running on a unix socket.
author | Stephan Bosch <stephan@rename-it.nl> |
---|---|
date | Sat, 25 Apr 2015 11:42:06 +0200 |
parents | f8ab4f979e92 |
children | 512a4792d9f5 |
files | src/lib-http/http-client-connection.c src/lib-http/http-client-host.c src/lib-http/http-client-peer.c src/lib-http/http-client-private.h src/lib-http/http-client-queue.c src/lib-http/http-client-request.c src/lib-http/http-client.h |
diffstat | 7 files changed, 286 insertions(+), 121 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-http/http-client-connection.c Sat Aug 29 14:42:49 2015 +0300 +++ b/src/lib-http/http-client-connection.c Sat Apr 25 11:42:06 2015 +0200 @@ -1015,7 +1015,7 @@ http_client_connection_ssl_handshaked(const char **error_r, void *context) { struct http_client_connection *conn = context; - const char *error, *host = conn->peer->addr.https_name; + const char *error, *host = conn->peer->addr.a.tcp.https_name; if (ssl_iostream_check_cert_validity(conn->ssl_iostream, host, &error) == 0) http_client_connection_debug(conn, "SSL handshake successful"); @@ -1049,7 +1049,7 @@ http_client_connection_debug(conn, "Starting SSL handshake"); if (io_stream_create_ssl_client(conn->client->ssl_ctx, - conn->peer->addr.https_name, &ssl_set, + conn->peer->addr.a.tcp.https_name, &ssl_set, &conn->conn.input, &conn->conn.output, &conn->ssl_iostream, &error) < 0) { *error_r = t_strdup_printf( @@ -1089,7 +1089,7 @@ } else { conn->connected_timestamp = ioloop_timeval; http_client_connection_debug(conn, "Connected"); - if (conn->peer->addr.https_name != NULL) { + if (http_client_peer_addr_is_https(&conn->peer->addr)) { if (http_client_connection_ssl_init(conn, &error) < 0) { http_client_peer_connection_failure(conn->peer, error); http_client_connection_debug(conn, "%s", error); @@ -1104,7 +1104,8 @@ static const struct connection_settings http_client_connection_set = { .input_max_size = (size_t)-1, .output_max_size = (size_t)-1, - .client = TRUE + .client = TRUE, + .delayed_unix_client_connected_callback = TRUE }; static const struct connection_vfuncs http_client_connection_vfuncs = { @@ -1248,6 +1249,9 @@ case HTTP_CLIENT_PEER_ADDR_RAW: conn_type = "Raw"; break; + case HTTP_CLIENT_PEER_ADDR_UNIX: + conn_type = "Unix"; + break; } conn = i_new(struct http_client_connection, 1); @@ -1258,11 +1262,20 @@ if (peer->addr.type != HTTP_CLIENT_PEER_ADDR_RAW) i_array_init(&conn->request_wait_list, 16); - if (peer->addr.type == HTTP_CLIENT_PEER_ADDR_HTTPS_TUNNEL) { - http_client_connection_connect_tunnel(conn, &addr->ip, addr->port); - } else { - connection_init_client_ip - (peer->client->conn_list, &conn->conn, &addr->ip, addr->port); + switch (peer->addr.type) { + case HTTP_CLIENT_PEER_ADDR_HTTPS_TUNNEL: + http_client_connection_connect_tunnel + (conn, &addr->a.tcp.ip, addr->a.tcp.port); + break; + case HTTP_CLIENT_PEER_ADDR_UNIX: + connection_init_client_unix(peer->client->conn_list, &conn->conn, + addr->a.un.path); + conn->connect_initialized = TRUE; + http_client_connection_connect(conn); + break; + default: + connection_init_client_ip(peer->client->conn_list, &conn->conn, + &addr->a.tcp.ip, addr->a.tcp.port); conn->connect_initialized = TRUE; http_client_connection_connect(conn); }
--- a/src/lib-http/http-client-host.c Sat Aug 29 14:42:49 2015 +0300 +++ b/src/lib-http/http-client-host.c Sat Apr 25 11:42:06 2015 +0200 @@ -137,31 +137,55 @@ } } +static struct http_client_host *http_client_host_create +(struct http_client *client) +{ + struct http_client_host *host; + + // FIXME: limit the maximum number of inactive cached hosts + host = i_new(struct http_client_host, 1); + host->client = client; + i_array_init(&host->queues, 4); + DLLIST_PREPEND(&client->hosts_list, host); + + return host; +} + struct http_client_host *http_client_host_get (struct http_client *client, const struct http_url *host_url) { struct http_client_host *host; - const char *hostname = host_url->host_name; - host = hash_table_lookup(client->hosts, hostname); - if (host == NULL) { - // FIXME: limit the maximum number of inactive cached hosts - host = i_new(struct http_client_host, 1); - host->client = client; - host->name = i_strdup(hostname); - i_array_init(&host->queues, 4); + if (host_url == NULL) { + host = client->unix_host; + if (host == NULL) { + host = http_client_host_create(client); + host->name = i_strdup("[unix]"); + host->unix_local = TRUE; - hostname = host->name; - hash_table_insert(client->hosts, hostname, host); - DLLIST_PREPEND(&client->hosts_list, host); + client->unix_host = host; - if (host_url->have_host_ip) { - host->ips_count = 1; - host->ips = i_new(struct ip_addr, host->ips_count); - host->ips[0] = host_url->host_ip; + http_client_host_debug(host, "Unix host created"); } - http_client_host_debug(host, "Host created"); + } else { + const char *hostname = host_url->host_name; + + host = hash_table_lookup(client->hosts, hostname); + if (host == NULL) { + host = http_client_host_create(client); + host->name = i_strdup(hostname); + hostname = host->name; + hash_table_insert(client->hosts, hostname, host); + + if (host_url->have_host_ip) { + host->ips_count = 1; + host->ips = i_new(struct ip_addr, host->ips_count); + host->ips[0] = host_url->host_ip; + } + + http_client_host_debug(host, "Host created"); + } } return host; } @@ -170,13 +194,14 @@ struct http_client_request *req) { struct http_client_queue *queue; - const struct http_url *host_url = req->host_url; struct http_client_peer_addr addr; const char *error; req->host = host; - if (host_url->have_ssl && host->client->ssl_ctx == NULL) { + http_client_request_get_peer_addr(req, &addr); + if (http_client_peer_addr_is_https(&addr) && + host->client->ssl_ctx == NULL) { if (http_client_init_ssl_ctx(host->client, &error) < 0) { http_client_request_error(req, HTTP_CLIENT_REQUEST_ERROR_CONNECT_FAILED, error); @@ -184,12 +209,15 @@ } } - http_client_request_get_peer_addr(req, &addr); - /* add request to queue (grouped by tcp port) */ queue = http_client_queue_create(host, &addr); http_client_queue_submit_request(queue, req); + if (host->unix_local) { + http_client_queue_connection_setup(queue); + return; + } + /* start DNS lookup if necessary */ if (host->ips_count == 0 && host->dns_lookup == NULL) http_client_host_lookup(host); @@ -210,7 +238,8 @@ http_client_host_debug(host, "Host destroy"); DLLIST_REMOVE(&host->client->hosts_list, host); - hash_table_remove(host->client->hosts, hostname); + if (host != host->client->unix_host) + hash_table_remove(host->client->hosts, hostname); if (host->dns_lookup != NULL) dns_lookup_abort(&host->dns_lookup);
--- a/src/lib-http/http-client-peer.c Sat Aug 29 14:42:49 2015 +0300 +++ b/src/lib-http/http-client-peer.c Sat Apr 25 11:42:06 2015 +0200 @@ -45,13 +45,16 @@ { switch (peer->type) { case HTTP_CLIENT_PEER_ADDR_RAW: - return net_ip_hash(&peer->ip) + peer->port + 1; + return net_ip_hash(&peer->a.tcp.ip) + peer->a.tcp.port + 1; case HTTP_CLIENT_PEER_ADDR_HTTP: - return net_ip_hash(&peer->ip) + peer->port; + return net_ip_hash(&peer->a.tcp.ip) + peer->a.tcp.port; case HTTP_CLIENT_PEER_ADDR_HTTPS: case HTTP_CLIENT_PEER_ADDR_HTTPS_TUNNEL: - return net_ip_hash(&peer->ip) + peer->port + - (peer->https_name == NULL ? 0 : str_hash(peer->https_name)); + return net_ip_hash(&peer->a.tcp.ip) + peer->a.tcp.port + + (peer->a.tcp.https_name == NULL ? + 0 : str_hash(peer->a.tcp.https_name)); + case HTTP_CLIENT_PEER_ADDR_UNIX: + return str_hash(peer->a.un.path); } i_unreached(); return 0; @@ -65,13 +68,24 @@ if (peer1->type != peer2->type) return (peer1->type > peer2->type ? 1 : -1); - if ((ret=net_ip_cmp(&peer1->ip, &peer2->ip)) != 0) - return ret; - if (peer1->port != peer2->port) - return (peer1->port > peer2->port ? 1 : -1); - if (peer1->type != HTTP_CLIENT_PEER_ADDR_HTTPS) - return 0; - return null_strcmp(peer1->https_name, peer2->https_name); + switch (peer1->type) { + case HTTP_CLIENT_PEER_ADDR_RAW: + case HTTP_CLIENT_PEER_ADDR_HTTP: + case HTTP_CLIENT_PEER_ADDR_HTTPS: + case HTTP_CLIENT_PEER_ADDR_HTTPS_TUNNEL: + if ((ret=net_ip_cmp(&peer1->a.tcp.ip, &peer2->a.tcp.ip)) != 0) + return ret; + if (peer1->a.tcp.port != peer2->a.tcp.port) + return (peer1->a.tcp.port > peer2->a.tcp.port ? 1 : -1); + if (peer1->type != HTTP_CLIENT_PEER_ADDR_HTTPS) + return 0; + return null_strcmp + (peer1->a.tcp.https_name, peer2->a.tcp.https_name); + case HTTP_CLIENT_PEER_ADDR_UNIX: + return null_strcmp(peer1->a.un.path, peer2->a.un.path); + } + i_unreached(); + return 0; } /* @@ -438,13 +452,25 @@ { struct http_client_peer *peer; - i_assert(addr->https_name == NULL || client->ssl_ctx != NULL); - peer = i_new(struct http_client_peer, 1); peer->client = client; peer->addr = *addr; - peer->https_name = i_strdup(addr->https_name); - peer->addr.https_name = peer->https_name; + + switch (addr->type) { + case HTTP_CLIENT_PEER_ADDR_HTTPS: + case HTTP_CLIENT_PEER_ADDR_HTTPS_TUNNEL: + i_assert(client->ssl_ctx != NULL); + peer->addr_name = i_strdup(addr->a.tcp.https_name); + peer->addr.a.tcp.https_name = peer->addr_name; + break; + case HTTP_CLIENT_PEER_ADDR_UNIX: + peer->addr_name = i_strdup(addr->a.un.path); + peer->addr.a.un.path = peer->addr_name; + break; + default: + break; + } + i_array_init(&peer->queues, 16); i_array_init(&peer->conns, 16); @@ -479,7 +505,7 @@ (peer->client->peers, (const struct http_client_peer_addr *)&peer->addr); DLLIST_REMOVE(&peer->client->peers_list, peer); - i_free(peer->https_name); + i_free(peer->addr_name); i_free(peer); *_peer = NULL; }
--- a/src/lib-http/http-client-private.h Sat Aug 29 14:42:49 2015 +0300 +++ b/src/lib-http/http-client-private.h Sat Apr 25 11:42:06 2015 +0200 @@ -38,14 +38,22 @@ HTTP_CLIENT_PEER_ADDR_HTTP = 0, HTTP_CLIENT_PEER_ADDR_HTTPS, HTTP_CLIENT_PEER_ADDR_HTTPS_TUNNEL, - HTTP_CLIENT_PEER_ADDR_RAW + HTTP_CLIENT_PEER_ADDR_RAW, + HTTP_CLIENT_PEER_ADDR_UNIX, }; struct http_client_peer_addr { enum http_client_peer_addr_type type; - const char *https_name; /* TLS SNI */ - struct ip_addr ip; - in_port_t port; + union { + struct { + const char *https_name; /* TLS SNI */ + struct ip_addr ip; + in_port_t port; + } tcp; + struct { + const char *path; + } un; + } a; }; struct http_client_request { @@ -59,6 +67,7 @@ struct http_url origin_url; const char *username, *password; + const char *host_socket; const struct http_url *host_url; const char *authority; @@ -157,7 +166,7 @@ struct http_client_peer { struct http_client_peer_addr addr; - char *https_name; + char *addr_name; struct http_client *client; struct http_client_peer *prev, *next; @@ -189,7 +198,7 @@ char *name; struct http_client_peer_addr addr; - char *https_name; + char *addr_name; /* current index in host->ips */ unsigned int ips_connect_idx; @@ -232,6 +241,8 @@ /* active DNS lookup */ struct dns_lookup *dns_lookup; + + unsigned int unix_local:1; }; struct http_client { @@ -249,6 +260,7 @@ struct connection_list *conn_list; HASH_TABLE_TYPE(http_client_host) hosts; + struct http_client_host *unix_host; struct http_client_host *hosts_list; HASH_TABLE_TYPE(http_client_peer) peers; struct http_client_peer *peers_list; @@ -262,6 +274,8 @@ void http_client_request_unref(struct http_client_request **_req); int http_client_request_delay_from_response(struct http_client_request *req, const struct http_response *response); +void http_client_request_get_peer_addr(const struct http_client_request *req, + struct http_client_peer_addr *addr); enum http_response_payload_type http_client_request_get_payload_type(struct http_client_request *req); int http_client_request_send(struct http_client_request *req, @@ -378,12 +392,53 @@ struct http_client_request *req); +static inline bool +http_client_peer_addr_is_https(const struct http_client_peer_addr *addr) +{ + switch (addr->type) { + case HTTP_CLIENT_PEER_ADDR_HTTPS: + case HTTP_CLIENT_PEER_ADDR_HTTPS_TUNNEL: + return TRUE; + default: + break; + } + return FALSE; +} + +static inline const char * +http_client_peer_addr_get_https_name(const struct http_client_peer_addr *addr) +{ + switch (addr->type) { + case HTTP_CLIENT_PEER_ADDR_HTTPS: + case HTTP_CLIENT_PEER_ADDR_HTTPS_TUNNEL: + return addr->a.tcp.https_name; + default: + break; + } + return NULL; +} + static inline const char * http_client_peer_addr2str(const struct http_client_peer_addr *addr) { - if (addr->ip.family == AF_INET6) - return t_strdup_printf("[%s]:%u", net_ip2addr(&addr->ip), addr->port); - return t_strdup_printf("%s:%u", net_ip2addr(&addr->ip), addr->port); + switch (addr->type) { + case HTTP_CLIENT_PEER_ADDR_HTTP: + case HTTP_CLIENT_PEER_ADDR_HTTPS: + case HTTP_CLIENT_PEER_ADDR_HTTPS_TUNNEL: + case HTTP_CLIENT_PEER_ADDR_RAW: + if (addr->a.tcp.ip.family == AF_INET6) { + return t_strdup_printf("[%s]:%u", + net_ip2addr(&addr->a.tcp.ip), addr->a.tcp.port); + } + return t_strdup_printf("%s:%u", + net_ip2addr(&addr->a.tcp.ip), addr->a.tcp.port); + case HTTP_CLIENT_PEER_ADDR_UNIX: + return t_strdup_printf("unix:%s", addr->a.un.path); + default: + break; + } + i_unreached(); + return ""; } static inline const char * @@ -396,29 +451,6 @@ return req->label; } -static inline void -http_client_request_get_peer_addr(const struct http_client_request *req, - struct http_client_peer_addr *addr) -{ - const struct http_url *host_url = req->host_url; - - memset(addr, 0, sizeof(*addr)); - if (req->connect_direct) { - addr->type = HTTP_CLIENT_PEER_ADDR_RAW; - addr->port = (host_url->have_port ? host_url->port : HTTPS_DEFAULT_PORT); - } else if (host_url->have_ssl) { - if (req->ssl_tunnel) - addr->type = HTTP_CLIENT_PEER_ADDR_HTTPS_TUNNEL; - else - addr->type = HTTP_CLIENT_PEER_ADDR_HTTPS; - addr->https_name = host_url->host_name; - addr->port = (host_url->have_port ? host_url->port : HTTPS_DEFAULT_PORT); - } else { - addr->type = HTTP_CLIENT_PEER_ADDR_HTTP; - addr->port = (host_url->have_port ? host_url->port : HTTP_DEFAULT_PORT); - } -} - static inline bool http_client_request_to_proxy(const struct http_client_request *req) {
--- a/src/lib-http/http-client-queue.c Sat Aug 29 14:42:49 2015 +0300 +++ b/src/lib-http/http-client-queue.c Sat Apr 25 11:42:06 2015 +0200 @@ -62,8 +62,7 @@ array_foreach_modifiable(&host->queues, queue_idx) { struct http_client_queue *queue = *queue_idx; - if (queue->addr.type == addr->type && queue->addr.port == addr->port && - null_strcmp(queue->addr.https_name, addr->https_name) == 0) + if (http_client_peer_addr_cmp(&queue->addr, addr) == 0) return queue; } @@ -78,30 +77,38 @@ queue = http_client_queue_find(host, addr); if (queue == NULL) { - char *name; + queue = i_new(struct http_client_queue, 1); + queue->client = host->client; + queue->host = host; + queue->addr = *addr; switch (addr->type) { case HTTP_CLIENT_PEER_ADDR_RAW: - name = i_strdup_printf("raw://%s:%u", host->name, addr->port); + queue->name = + i_strdup_printf("raw://%s:%u", host->name, addr->a.tcp.port); + queue->addr.a.tcp.https_name = NULL; break; case HTTP_CLIENT_PEER_ADDR_HTTPS_TUNNEL: case HTTP_CLIENT_PEER_ADDR_HTTPS: - name = i_strdup_printf("https://%s:%u", host->name, addr->port); + queue->name = + i_strdup_printf("https://%s:%u", host->name, addr->a.tcp.port); + queue->addr_name = i_strdup(addr->a.tcp.https_name); + queue->addr.a.tcp.https_name = queue->addr_name; break; case HTTP_CLIENT_PEER_ADDR_HTTP: - name = i_strdup_printf("http://%s:%u", host->name, addr->port); + queue->name = + i_strdup_printf("http://%s:%u", host->name, addr->a.tcp.port); + queue->addr.a.tcp.https_name = NULL; + break; + case HTTP_CLIENT_PEER_ADDR_UNIX: + queue->name = i_strdup_printf("unix:%s", addr->a.un.path); + queue->addr_name = i_strdup(addr->a.un.path); + queue->addr.a.un.path = queue->addr_name; break; default: i_unreached(); } - queue = i_new(struct http_client_queue, 1); - queue->client = host->client; - queue->host = host; - queue->addr = *addr; - queue->https_name = i_strdup(addr->https_name); - queue->addr.https_name = queue->https_name; - queue->name = name; queue->ips_connect_idx = 0; i_array_init(&queue->requests, 16); i_array_init(&queue->queued_requests, 16); @@ -117,7 +124,6 @@ { http_client_queue_fail (queue, HTTP_CLIENT_REQUEST_ERROR_ABORTED, "Aborted"); - i_free(queue->https_name); if (array_is_created(&queue->pending_peers)) array_free(&queue->pending_peers); array_free(&queue->requests); @@ -128,6 +134,7 @@ timeout_remove(&queue->to_connect); if (queue->to_delayed != NULL) timeout_remove(&queue->to_delayed); + i_free(queue->addr_name); i_free(queue->name); i_free(queue); } @@ -169,6 +176,7 @@ &queue->client->set; struct http_client_host *host = queue->host; + i_assert(queue->addr.type != HTTP_CLIENT_PEER_ADDR_UNIX); i_assert(queue->ips_connect_idx < host->ips_count); i_assert(queue->ips_connect_start_idx < host->ips_count); @@ -190,6 +198,9 @@ { struct http_client_host *host = queue->host; const struct http_client_peer_addr *addr = &queue->addr; + const char *https_name; + + i_assert(queue->addr.type != HTTP_CLIENT_PEER_ADDR_UNIX); if (queue->to_connect != NULL) timeout_remove(&queue->to_connect); @@ -202,10 +213,11 @@ /* if our our previous connection attempt takes longer than the soft_connect_timeout, we start a connection attempt to the next IP in parallel */ + https_name = http_client_peer_addr_get_https_name(addr); http_client_queue_debug(queue, "Connection to %s%s is taking a long time; " "starting parallel connection attempt to next IP", - http_client_peer_addr2str(addr), addr->https_name == NULL ? "" : - t_strdup_printf(" (SSL=%s)", addr->https_name)); + http_client_peer_addr2str(addr), (https_name == NULL ? "" : + t_strdup_printf(" (SSL=%s)", https_name))); /* next IP */ queue->ips_connect_idx = (queue->ips_connect_idx + 1) % host->ips_count; @@ -222,18 +234,22 @@ unsigned int num_requests = array_count(&queue->queued_requests) + array_count(&queue->queued_urgent_requests); + const char *ssl = ""; if (num_requests == 0) return; /* update our peer address */ - i_assert(queue->ips_connect_idx < host->ips_count); - queue->addr.ip = host->ips[queue->ips_connect_idx]; + if (queue->addr.type != HTTP_CLIENT_PEER_ADDR_UNIX) { + i_assert(queue->ips_connect_idx < host->ips_count); + queue->addr.a.tcp.ip = host->ips[queue->ips_connect_idx]; + ssl = http_client_peer_addr_get_https_name(addr); + ssl = (ssl == NULL ? "" : t_strdup_printf(" (SSL=%s)", ssl)); + } http_client_queue_debug(queue, "Setting up connection to %s%s " - "(%u requests pending)", http_client_peer_addr2str(addr), - (addr->https_name == NULL ? "" : - t_strdup_printf(" (SSL=%s)", addr->https_name)), num_requests); + "(%u requests pending)", http_client_peer_addr2str(addr), ssl, + num_requests); /* create/get peer */ @@ -263,19 +279,20 @@ } if (new_peer) { http_client_queue_debug(queue, "Started new connection to %s%s", - http_client_peer_addr2str(addr), (addr->https_name == NULL ? "" : - t_strdup_printf(" (SSL=%s)", addr->https_name))); + http_client_peer_addr2str(addr), ssl); array_append(&queue->pending_peers, &peer, 1); queue->connect_attempts++; } /* start soft connect time-out (but only if we have another IP left) */ - msecs = host->client->set.soft_connect_timeout_msecs; - if (!http_client_queue_is_last_connect_ip(queue) && msecs > 0 && - queue->to_connect == NULL) { - queue->to_connect = - timeout_add(msecs, http_client_queue_soft_connect_timeout, queue); + if (queue->addr.type != HTTP_CLIENT_PEER_ADDR_UNIX) { + msecs = host->client->set.soft_connect_timeout_msecs; + if (!http_client_queue_is_last_connect_ip(queue) && msecs > 0 && + queue->to_connect == NULL) { + queue->to_connect = + timeout_add(msecs, http_client_queue_soft_connect_timeout, queue); + } } } } @@ -284,9 +301,11 @@ http_client_queue_connection_success(struct http_client_queue *queue, const struct http_client_peer_addr *addr) { - /* we achieved at least one connection the the addr->ip */ - queue->ips_connect_start_idx = - http_client_host_get_ip_idx(queue->host, &addr->ip); + if (queue->addr.type != HTTP_CLIENT_PEER_ADDR_UNIX) { + /* we achieved at least one connection the the addr->ip */ + queue->ips_connect_start_idx = + http_client_host_get_ip_idx(queue->host, &addr->a.tcp.ip); + } /* reset attempt counter */ queue->connect_attempts = 0; @@ -325,14 +344,16 @@ { const struct http_client_settings *set = &queue->client->set; + const char *https_name = http_client_peer_addr_get_https_name(addr); struct http_client_host *host = queue->host; - http_client_queue_debug(queue, "Failed to set up connection to %s%s: %s " + http_client_queue_debug(queue, + "Failed to set up connection to %s%s: %s " "(%u peers pending, %u requests pending)", http_client_peer_addr2str(addr), - (addr->https_name == NULL ? "" : - t_strdup_printf(" (SSL=%s)", addr->https_name)), reason, - (array_is_created(&queue->pending_peers) ? + (https_name == NULL ? "" : + t_strdup_printf(" (SSL=%s)", https_name)), + reason, (array_is_created(&queue->pending_peers) ? array_count(&queue->pending_peers): 0), array_count(&queue->requests)); @@ -364,6 +385,12 @@ if (queue->to_connect != NULL) timeout_remove(&queue->to_connect); + if (queue->addr.type == HTTP_CLIENT_PEER_ADDR_UNIX) { + http_client_queue_fail(queue, + HTTP_CLIENT_REQUEST_ERROR_CONNECT_FAILED, reason); + return; + } + if (http_client_queue_is_last_connect_ip(queue)) { /* all IPs failed, but retry all of them again if we have more connect attempts left or on the next request. */
--- a/src/lib-http/http-client-request.c Sat Aug 29 14:42:49 2015 +0300 +++ b/src/lib-http/http-client-request.c Sat Apr 25 11:42:06 2015 +0200 @@ -442,7 +442,9 @@ { struct http_client *client = req->client; struct http_client_host *host; + const char *proxy_socket_path = client->set.proxy_socket_path; const struct http_url *proxy_url = client->set.proxy_url; + bool have_proxy = (proxy_socket_path != NULL) || (proxy_url != NULL); const char *authority, *target; i_assert(req->state == HTTP_REQUEST_STATE_NEW); @@ -458,16 +460,20 @@ } /* determine what host to contact to submit this request */ - if (proxy_url != NULL) { + if (have_proxy) { if (req->origin_url.have_ssl && !client->set.no_ssl_tunnel && !req->connect_tunnel) { - req->host_url = &req->origin_url; /* tunnel to origin server */ + req->host_url = &req->origin_url; /* tunnel to origin server */ req->ssl_tunnel = TRUE; + } else if (proxy_socket_path != NULL) { + req->host_socket = proxy_socket_path; /* proxy on unix socket */ + req->host_url = NULL; } else { - req->host_url = proxy_url; /* proxy server */ + req->host_url = proxy_url; /* normal proxy server */ + req->host_socket = NULL; } } else { - req->host_url = &req->origin_url; /* origin server */ + req->host_url = &req->origin_url; /* origin server */ } /* use submission date if no date is set explicitly */ @@ -481,10 +487,10 @@ req->label = p_strdup_printf(req->pool, "[%s %s]", req->method, target); /* update request target */ - if (req->connect_tunnel || proxy_url != NULL) + if (req->connect_tunnel || have_proxy) req->target = p_strdup(req->pool, target); - if (proxy_url == NULL) { + if (!have_proxy) { /* if we don't have a proxy, CONNECT requests are handled by creating the requested connection directly */ req->connect_direct = req->connect_tunnel; @@ -522,6 +528,36 @@ client->requests_count++; } +void +http_client_request_get_peer_addr(const struct http_client_request *req, + struct http_client_peer_addr *addr) +{ + const char *host_socket = req->host_socket; + const struct http_url *host_url = req->host_url; + + memset(addr, 0, sizeof(*addr)); + if (host_socket != NULL) { + addr->type = HTTP_CLIENT_PEER_ADDR_UNIX; + addr->a.un.path = host_socket; + } else if (req->connect_direct) { + addr->type = HTTP_CLIENT_PEER_ADDR_RAW; + addr->a.tcp.port = + (host_url->have_port ? host_url->port : HTTPS_DEFAULT_PORT); + } else if (host_url->have_ssl) { + if (req->ssl_tunnel) + addr->type = HTTP_CLIENT_PEER_ADDR_HTTPS_TUNNEL; + else + addr->type = HTTP_CLIENT_PEER_ADDR_HTTPS; + addr->a.tcp.https_name = host_url->host_name; + addr->a.tcp.port = + (host_url->have_port ? host_url->port : HTTPS_DEFAULT_PORT); + } else { + addr->type = HTTP_CLIENT_PEER_ADDR_HTTP; + addr->a.tcp.port = + (host_url->have_port ? host_url->port : HTTP_DEFAULT_PORT); + } +} + static void http_client_request_finish_payload_out(struct http_client_request *req) {
--- a/src/lib-http/http-client.h Sat Aug 29 14:42:49 2015 +0300 +++ b/src/lib-http/http-client.h Sat Apr 25 11:42:06 2015 +0200 @@ -51,9 +51,11 @@ /* User-Agent: header (default: none) */ const char *user_agent; - /* configuration for using a proxy */ - const char *proxy_socket_path; /* FIXME: implement */ + /* proxy on unix socket */ + const char *proxy_socket_path; + /* URL for normal proxy (ignored if proxy_socket_path is set) */ const struct http_url *proxy_url; + /* credentials for proxy */ const char *proxy_username; const char *proxy_password;