]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-http: client: Added support for attempting a single IP several times.
authorStephan Bosch <stephan@rename-it.nl>
Wed, 10 Sep 2014 10:39:37 +0000 (13:39 +0300)
committerStephan Bosch <stephan@rename-it.nl>
Wed, 10 Sep 2014 10:39:37 +0000 (13:39 +0300)
Also limits the number of attempts when there are many IPs.

src/lib-http/http-client-private.h
src/lib-http/http-client-queue.c
src/lib-http/http-client.c
src/lib-http/http-client.h

index 23016e48404d918241965c9db5314c94b6ad5a30..3a942155d388831281a9c9281a2c23f0263a7391 100644 (file)
@@ -182,6 +182,8 @@ struct http_client_queue {
           connected IP */
        unsigned int ips_connect_start_idx;
 
+       unsigned int connect_attempts;
+
        /* peers we are trying to connect to;
           this can be more than one when soft connect timeouts are enabled */
        ARRAY_TYPE(http_client_peer) pending_peers;
index 387f46f7b223c86a3049837f358587e0acec3917..d23df71a0e1739e7baa1a721a9b8d8cfc0af3254 100644 (file)
@@ -158,13 +158,20 @@ http_client_queue_drop_request(struct http_client_queue *queue,
 static bool
 http_client_queue_is_last_connect_ip(struct http_client_queue *queue)
 {
+       const struct http_client_settings *set =
+               &queue->client->set;
        struct http_client_host *host = queue->host;
 
        i_assert(queue->ips_connect_idx < host->ips_count);
        i_assert(queue->ips_connect_start_idx < host->ips_count);
 
-       /* we'll always go through all the IPs. we don't necessarily start
-          connecting from the first IP, so we'll need to treat the IPs as
+       /* if a maximum connect attempts > 1 is set, enforce it directly */
+       if (set->max_connect_attempts > 1) {
+               return queue->connect_attempts >= set->max_connect_attempts;
+       }
+               
+       /* otherwise, we'll always go through all the IPs. we don't necessarily
+          start connecting from the first IP, so we'll need to treat the IPs as
           a ring buffer where we automatically wrap back to the first IP
           when necessary. */
        return (queue->ips_connect_idx + 1) % host->ips_count ==
@@ -244,8 +251,14 @@ void http_client_queue_connection_setup(struct http_client_queue *queue)
                                }
                        }
                }
-               if (new_peer)
+               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)));
+
                        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;
@@ -265,6 +278,9 @@ http_client_queue_connection_success(struct http_client_queue *queue,
        queue->ips_connect_start_idx =
                http_client_host_get_ip_idx(queue->host, &addr->ip);
 
+       /* reset attempt counter */
+       queue->connect_attempts = 0;
+
        /* stop soft connect time-out */
        if (queue->to_connect != NULL)
                timeout_remove(&queue->to_connect);
@@ -343,6 +359,7 @@ http_client_queue_connection_failure(struct http_client_queue *queue,
                   next request. */
                queue->ips_connect_idx = queue->ips_connect_start_idx =
                        (queue->ips_connect_idx + 1) % host->ips_count;
+               queue->connect_attempts = 0;
                http_client_queue_fail(queue,
                        HTTP_CLIENT_REQUEST_ERROR_CONNECT_FAILED, reason);
                return FALSE;
index 441ffba04709b94ce74495338e5ad199fb7347d8..be368ddf04afc444ceab913566cb040e4f0138d0 100644 (file)
@@ -120,6 +120,7 @@ struct http_client *http_client_init(const struct http_client_settings *set)
        client->set.max_pipelined_requests =
                (set->max_pipelined_requests > 0 ? set->max_pipelined_requests : 1);
        client->set.max_attempts = set->max_attempts;
+       client->set.max_connect_attempts = set->max_connect_attempts;
        client->set.no_auto_redirect = set->no_auto_redirect;
        client->set.no_ssl_tunnel = set->no_ssl_tunnel;
        client->set.max_redirects = set->max_redirects;
index 61705bb033333c377ae6b665fbcc8da385a42e5d..21ccff92c9ce81f31474e7ea16edf801494d0723 100644 (file)
@@ -81,6 +81,17 @@ struct http_client_settings {
        /* maximum number of attempts for a request */
        unsigned int max_attempts;
 
+       /* maximum number of connection attempts to a host before all associated
+          requests fail.
+
+     if > 1, the maximum will be enforced across all IPs for that host,
+          meaning that IPs may be tried more than once eventually if the number
+          of IPs is smaller than the specified maximum attempts. If the number of IPs
+          is higher than the maximum attempts, not all IPs are tried. If <= 1, all
+          IPs are tried at most once.
+        */
+       unsigned int max_connect_attempts;
+
        /* response header limits */
        struct http_header_limits response_hdr_limits;