http-client-host.c revision 2300bdf148ee501082947c2ec79d12c175489897
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2013-2017 Dovecot authors, see the included COPYING file */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "lib.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "net.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "str.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "hash.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "array.h"
aacf2a69acc59e9382578d6f4e030788abc79706Timo Sirainen#include "llist.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "ioloop.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "istream.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "ostream.h"
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch#include "time-util.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "dns-lookup.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "http-response-parser.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "http-client-private.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
c4b2dba355010a38f17b3cd84feb01ecb8b05a55Stephan Bosch#define HTTP_CLIENT_HOST_MINIMUM_IDLE_TIMEOUT_MSECS 100
c4b2dba355010a38f17b3cd84feb01ecb8b05a55Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch/*
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch * Logging
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschstatic inline void
7384b4e78eaab44693c985192276e31322155e32Stephan Boschhttp_client_host_debug(struct http_client_host *host,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch const char *format, ...) ATTR_FORMAT(2, 3);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschstatic inline void
7384b4e78eaab44693c985192276e31322155e32Stephan Boschhttp_client_host_debug(struct http_client_host *host,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch const char *format, ...)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch va_list args;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (host->client->set.debug) {
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch va_start(args, format);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch i_debug("http-client: host %s: %s",
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch host->name, t_strdup_vprintf(format, args));
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch va_end(args);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
70505f4839520ac67895992621c97d2480c22e7fTimo Sirainen/*
70505f4839520ac67895992621c97d2480c22e7fTimo Sirainen * Host
70505f4839520ac67895992621c97d2480c22e7fTimo Sirainen */
70505f4839520ac67895992621c97d2480c22e7fTimo Sirainen
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Boschstatic void
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Boschhttp_client_host_idle_timeout(struct http_client_host *host)
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch{
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch http_client_host_debug(host, "Idle host timed out");
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch http_client_host_free(&host);
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch}
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Boschvoid http_client_host_check_idle(struct http_client_host *host)
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch{
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch struct http_client_queue *const *queue_idx;
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch unsigned int requests = 0;
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch int timeout = 0;
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch if (host->to_idle != NULL)
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch return;
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch array_foreach(&host->queues, queue_idx) {
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch requests += http_client_queue_requests_active(*queue_idx);
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch }
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch if (requests > 0)
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch return;
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch if (!host->unix_local && !host->explicit_ip &&
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch host->ips_timeout.tv_sec > 0) {
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch timeout = timeval_diff_msecs
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch (&host->ips_timeout, &ioloop_timeval);
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch }
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch if (timeout <= HTTP_CLIENT_HOST_MINIMUM_IDLE_TIMEOUT_MSECS)
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch timeout = HTTP_CLIENT_HOST_MINIMUM_IDLE_TIMEOUT_MSECS;
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch host->to_idle = timeout_add_short(timeout,
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch http_client_host_idle_timeout, host);
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch http_client_host_debug(host,
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch "Host is idle (timeout = %u msecs)", timeout);
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch}
fbe111ce65bb5af03314adbfa8bcde3f08c08641Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschstatic void
de96afeeaa5242cffe89f1966457e935806b5746Stephan Boschhttp_client_host_lookup_failure(struct http_client_host *host,
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch const char *error)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch struct http_client_queue *const *queue_idx;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
18d2775f815cdeed9bc1a2da078e682f5d354cf9Timo Sirainen error = t_strdup_printf("Failed to lookup host %s: %s",
18d2775f815cdeed9bc1a2da078e682f5d354cf9Timo Sirainen host->name, error);
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch array_foreach_modifiable(&host->queues, queue_idx) {
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Bosch http_client_queue_host_lookup_failure(*queue_idx, error);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
c4b2dba355010a38f17b3cd84feb01ecb8b05a55Stephan Bosch
c4b2dba355010a38f17b3cd84feb01ecb8b05a55Stephan Bosch http_client_host_check_idle(host);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschstatic void
7384b4e78eaab44693c985192276e31322155e32Stephan Boschhttp_client_host_dns_callback(const struct dns_lookup_result *result,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct http_client_host *host)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch struct http_client *client = host->client;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch struct http_client_queue *const *queue_idx;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch unsigned int requests = 0;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch host->dns_lookup = NULL;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (result->ret != 0) {
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch /* lookup failed */
18d2775f815cdeed9bc1a2da078e682f5d354cf9Timo Sirainen http_client_host_lookup_failure(host, result->error);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch http_client_host_debug(host,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch "DNS lookup successful; got %d IPs", result->ips_count);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch i_assert(result->ips_count > 0);
7fc4f555a9a12630932f73659bd575a4a94386ecTimo Sirainen host->ips = i_realloc_type(host->ips, struct ip_addr,
ae6a14ce9d4a49c4c500d96911dd969087a80851Timo Sirainen host->ips_count, result->ips_count);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch host->ips_count = result->ips_count;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch memcpy(host->ips, result->ips, sizeof(*host->ips) * host->ips_count);
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch host->ips_timeout = ioloop_timeval;
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch timeval_add_msecs(&host->ips_timeout, client->set.dns_ttl_msecs);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch /* make connections to requested ports */
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch array_foreach_modifiable(&host->queues, queue_idx) {
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch requests += http_client_queue_host_lookup_done(*queue_idx);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (requests == 0 && host->client->ioloop != NULL)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch io_loop_stop(host->client->ioloop);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschstatic void http_client_host_lookup
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch(struct http_client_host *host)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct http_client *client = host->client;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct dns_lookup_settings dns_set;
c936df07cf490f090f2f336f40ca386cc953b055Stephan Bosch struct ip_addr *ips;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch int ret;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
c936df07cf490f090f2f336f40ca386cc953b055Stephan Bosch i_assert(!host->explicit_ip);
c4b2dba355010a38f17b3cd84feb01ecb8b05a55Stephan Bosch i_assert(host->dns_lookup == NULL);
c4b2dba355010a38f17b3cd84feb01ecb8b05a55Stephan Bosch
c936df07cf490f090f2f336f40ca386cc953b055Stephan Bosch if (client->set.dns_client != NULL) {
7944646fad6aa1e7c649c3d33e454c516b0220b6Timo Sirainen http_client_host_debug(host,
7944646fad6aa1e7c649c3d33e454c516b0220b6Timo Sirainen "Performing asynchronous DNS lookup");
7944646fad6aa1e7c649c3d33e454c516b0220b6Timo Sirainen (void)dns_client_lookup(client->set.dns_client, host->name,
7944646fad6aa1e7c649c3d33e454c516b0220b6Timo Sirainen http_client_host_dns_callback, host, &host->dns_lookup);
81558ac5d0b1a23861870e084fa52cbc951ceda6Timo Sirainen } else if (client->set.dns_client_socket_path != NULL) {
7944646fad6aa1e7c649c3d33e454c516b0220b6Timo Sirainen http_client_host_debug(host,
7944646fad6aa1e7c649c3d33e454c516b0220b6Timo Sirainen "Performing asynchronous DNS lookup");
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&dns_set);
7944646fad6aa1e7c649c3d33e454c516b0220b6Timo Sirainen dns_set.dns_client_socket_path =
7944646fad6aa1e7c649c3d33e454c516b0220b6Timo Sirainen client->set.dns_client_socket_path;
5257840e8d31a6cb7051703b4cb0931c82aba638Stephan Bosch if (client->set.connect_timeout_msecs > 0)
5257840e8d31a6cb7051703b4cb0931c82aba638Stephan Bosch dns_set.timeout_msecs = client->set.connect_timeout_msecs;
5257840e8d31a6cb7051703b4cb0931c82aba638Stephan Bosch else if (client->set.request_timeout_msecs > 0)
5257840e8d31a6cb7051703b4cb0931c82aba638Stephan Bosch dns_set.timeout_msecs = client->set.request_timeout_msecs;
5257840e8d31a6cb7051703b4cb0931c82aba638Stephan Bosch else {
5257840e8d31a6cb7051703b4cb0931c82aba638Stephan Bosch dns_set.timeout_msecs =
5257840e8d31a6cb7051703b4cb0931c82aba638Stephan Bosch HTTP_CLIENT_DEFAULT_DNS_LOOKUP_TIMEOUT_MSECS;
5257840e8d31a6cb7051703b4cb0931c82aba638Stephan Bosch }
7944646fad6aa1e7c649c3d33e454c516b0220b6Timo Sirainen (void)dns_lookup(host->name, &dns_set,
7944646fad6aa1e7c649c3d33e454c516b0220b6Timo Sirainen http_client_host_dns_callback, host, &host->dns_lookup);
7944646fad6aa1e7c649c3d33e454c516b0220b6Timo Sirainen } else {
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch unsigned int ips_count;
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch
7944646fad6aa1e7c649c3d33e454c516b0220b6Timo Sirainen ret = net_gethostbyname(host->name, &ips, &ips_count);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (ret != 0) {
18d2775f815cdeed9bc1a2da078e682f5d354cf9Timo Sirainen http_client_host_lookup_failure(host, net_gethosterror(ret));
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch http_client_host_debug(host,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch "DNS lookup successful; got %d IPs", ips_count);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
c4b2dba355010a38f17b3cd84feb01ecb8b05a55Stephan Bosch i_free(host->ips);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch host->ips_count = ips_count;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch host->ips = i_new(struct ip_addr, ips_count);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch memcpy(host->ips, ips, ips_count * sizeof(*ips));
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch host->ips_timeout = ioloop_timeval;
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch timeval_add_msecs(&host->ips_timeout, client->set.dns_ttl_msecs);
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch }
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch}
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Boschint http_client_host_refresh(struct http_client_host *host)
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch{
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch if (host->unix_local)
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch return 0;
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch if (host->explicit_ip)
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch return 0;
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch if (host->dns_lookup != NULL)
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch return -1;
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch if (host->ips_count > 0 &&
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch timeval_cmp(&host->ips_timeout, &ioloop_timeval) > 0)
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch return 0;
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch
c4b2dba355010a38f17b3cd84feb01ecb8b05a55Stephan Bosch if (host->to_idle != NULL)
c4b2dba355010a38f17b3cd84feb01ecb8b05a55Stephan Bosch return 0;
c4b2dba355010a38f17b3cd84feb01ecb8b05a55Stephan Bosch
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch http_client_host_debug(host,
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch "IPs have expired; need to refresh DNS lookup");
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch http_client_host_lookup(host);
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch if (host->dns_lookup != NULL)
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch return -1;
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch return (host->ips_count > 0 ? 1 : -1);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Boschstatic struct http_client_host *http_client_host_create
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch(struct http_client *client)
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch{
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch struct http_client_host *host;
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch // FIXME: limit the maximum number of inactive cached hosts
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch host = i_new(struct http_client_host, 1);
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch host->client = client;
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch i_array_init(&host->queues, 4);
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch DLLIST_PREPEND(&client->hosts_list, host);
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch return host;
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch}
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschstruct http_client_host *http_client_host_get
e47c2f17d8136c4d972d1074a3f84ba2ecef4fdcStephan Bosch(struct http_client *client, const struct http_url *host_url)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct http_client_host *host;
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch if (host_url == NULL) {
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch host = client->unix_host;
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch if (host == NULL) {
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch host = http_client_host_create(client);
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch host->name = i_strdup("[unix]");
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch host->unix_local = TRUE;
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch client->unix_host = host;
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch http_client_host_debug(host, "Unix host created");
e47c2f17d8136c4d972d1074a3f84ba2ecef4fdcStephan Bosch }
e47c2f17d8136c4d972d1074a3f84ba2ecef4fdcStephan Bosch
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch } else {
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch const char *hostname = host_url->host.name;
c936df07cf490f090f2f336f40ca386cc953b055Stephan Bosch struct ip_addr ip = host_url->host.ip;
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch host = hash_table_lookup(client->hosts, hostname);
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch if (host == NULL) {
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch host = http_client_host_create(client);
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch host->name = i_strdup(hostname);
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch hostname = host->name;
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch hash_table_insert(client->hosts, hostname, host);
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch
c936df07cf490f090f2f336f40ca386cc953b055Stephan Bosch if (ip.family != 0 || net_addr2ip(host->name, &ip) == 0) {
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch host->ips_count = 1;
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch host->ips = i_new(struct ip_addr, host->ips_count);
c936df07cf490f090f2f336f40ca386cc953b055Stephan Bosch host->ips[0] = ip;
c936df07cf490f090f2f336f40ca386cc953b055Stephan Bosch host->explicit_ip = TRUE;
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch }
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch http_client_host_debug(host, "Host created");
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return host;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschvoid http_client_host_free(struct http_client_host **_host)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct http_client_host *host = *_host;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch struct http_client_queue *const *queue_idx;
c4b2dba355010a38f17b3cd84feb01ecb8b05a55Stephan Bosch ARRAY_TYPE(http_client_queue) queues;
aacf2a69acc59e9382578d6f4e030788abc79706Timo Sirainen const char *hostname = host->name;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch http_client_host_debug(host, "Host destroy");
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
c4b2dba355010a38f17b3cd84feb01ecb8b05a55Stephan Bosch if (host->to_idle != NULL)
c4b2dba355010a38f17b3cd84feb01ecb8b05a55Stephan Bosch timeout_remove(&host->to_idle);
c4b2dba355010a38f17b3cd84feb01ecb8b05a55Stephan Bosch
aacf2a69acc59e9382578d6f4e030788abc79706Timo Sirainen DLLIST_REMOVE(&host->client->hosts_list, host);
c4b2dba355010a38f17b3cd84feb01ecb8b05a55Stephan Bosch if (host == host->client->unix_host)
c4b2dba355010a38f17b3cd84feb01ecb8b05a55Stephan Bosch host->client->unix_host = NULL;
c4b2dba355010a38f17b3cd84feb01ecb8b05a55Stephan Bosch else
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch hash_table_remove(host->client->hosts, hostname);
aacf2a69acc59e9382578d6f4e030788abc79706Timo Sirainen
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (host->dns_lookup != NULL)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch dns_lookup_abort(&host->dns_lookup);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch /* drop request queues */
c4b2dba355010a38f17b3cd84feb01ecb8b05a55Stephan Bosch t_array_init(&queues, array_count(&host->queues));
c4b2dba355010a38f17b3cd84feb01ecb8b05a55Stephan Bosch array_copy(&queues.arr, 0,
c4b2dba355010a38f17b3cd84feb01ecb8b05a55Stephan Bosch &host->queues.arr, 0, array_count(&host->queues));
c4b2dba355010a38f17b3cd84feb01ecb8b05a55Stephan Bosch array_clear(&host->queues);
c4b2dba355010a38f17b3cd84feb01ecb8b05a55Stephan Bosch array_foreach(&queues, queue_idx) {
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch http_client_queue_free(*queue_idx);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch array_free(&host->queues);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch i_free(host->ips);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch i_free(host->name);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch i_free(host);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
2300bdf148ee501082947c2ec79d12c175489897Stephan Boschvoid http_client_host_submit_request(struct http_client_host *host,
2300bdf148ee501082947c2ec79d12c175489897Stephan Bosch struct http_client_request *req)
2300bdf148ee501082947c2ec79d12c175489897Stephan Bosch{
2300bdf148ee501082947c2ec79d12c175489897Stephan Bosch struct http_client_queue *queue;
2300bdf148ee501082947c2ec79d12c175489897Stephan Bosch struct http_client_peer_addr addr;
2300bdf148ee501082947c2ec79d12c175489897Stephan Bosch const char *error;
2300bdf148ee501082947c2ec79d12c175489897Stephan Bosch
2300bdf148ee501082947c2ec79d12c175489897Stephan Bosch req->host = host;
2300bdf148ee501082947c2ec79d12c175489897Stephan Bosch
2300bdf148ee501082947c2ec79d12c175489897Stephan Bosch http_client_request_get_peer_addr(req, &addr);
2300bdf148ee501082947c2ec79d12c175489897Stephan Bosch if (http_client_peer_addr_is_https(&addr) &&
2300bdf148ee501082947c2ec79d12c175489897Stephan Bosch host->client->ssl_ctx == NULL) {
2300bdf148ee501082947c2ec79d12c175489897Stephan Bosch if (http_client_init_ssl_ctx(host->client, &error) < 0) {
2300bdf148ee501082947c2ec79d12c175489897Stephan Bosch http_client_request_error(&req,
2300bdf148ee501082947c2ec79d12c175489897Stephan Bosch HTTP_CLIENT_REQUEST_ERROR_CONNECT_FAILED, error);
2300bdf148ee501082947c2ec79d12c175489897Stephan Bosch return;
2300bdf148ee501082947c2ec79d12c175489897Stephan Bosch }
2300bdf148ee501082947c2ec79d12c175489897Stephan Bosch }
2300bdf148ee501082947c2ec79d12c175489897Stephan Bosch
2300bdf148ee501082947c2ec79d12c175489897Stephan Bosch /* add request to queue (grouped by tcp port) */
2300bdf148ee501082947c2ec79d12c175489897Stephan Bosch queue = http_client_queue_get(host, &addr);
2300bdf148ee501082947c2ec79d12c175489897Stephan Bosch http_client_queue_submit_request(queue, req);
2300bdf148ee501082947c2ec79d12c175489897Stephan Bosch
2300bdf148ee501082947c2ec79d12c175489897Stephan Bosch /* cancel host idle timeout */
2300bdf148ee501082947c2ec79d12c175489897Stephan Bosch timeout_remove(&host->to_idle);
2300bdf148ee501082947c2ec79d12c175489897Stephan Bosch}
2300bdf148ee501082947c2ec79d12c175489897Stephan Bosch
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Boschbool http_client_host_get_ip_idx(struct http_client_host *host,
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch const struct ip_addr *ip, unsigned int *idx_r)
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch{
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch unsigned int i;
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch for (i = 0; i < host->ips_count; i++) {
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch if (net_ip_compare(&host->ips[i], ip)) {
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch *idx_r = i;
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch return TRUE;
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch }
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch }
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch return FALSE;
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch}
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschvoid http_client_host_switch_ioloop(struct http_client_host *host)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch struct http_client_queue *const *queue_idx;
6bc9fb43cc1ac24693d030a6cbfa43bc7cbc82cbTimo Sirainen
856ae2ad98cee79b2719911a3cc131d7f4ec8a90Timo Sirainen if (host->dns_lookup != NULL && host->client->set.dns_client == NULL)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch dns_lookup_switch_ioloop(host->dns_lookup);
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch array_foreach(&host->queues, queue_idx)
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch http_client_queue_switch_ioloop(*queue_idx);
c4b2dba355010a38f17b3cd84feb01ecb8b05a55Stephan Bosch if (host->to_idle != NULL)
c4b2dba355010a38f17b3cd84feb01ecb8b05a55Stephan Bosch host->to_idle = io_loop_move_timeout(&host->to_idle);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}