dovecot-2.2: http-client: Changed struct http_client_host_port i...

dovecot at dovecot.org dovecot at dovecot.org
Fri Nov 22 22:13:13 EET 2013


details:   http://hg.dovecot.org/dovecot-2.2/rev/160e489d7c12
changeset: 17002:160e489d7c12
user:      Stephan Bosch <stephan at rename-it.nl>
date:      Fri Nov 22 22:07:41 2013 +0200
description:
http-client: Changed struct http_client_host_port into a struct http_client_queue object.
Peer and request objects now reference the queue object directly rather
than the host object. This way, there is no need to find the matching
host:port in the host anymore. This makes the queueing structure more
intuitive and more efficient. This is a first step towards support for
connecting to HTTP services through unix sockets or directing requests at
specific hosts (so not from the URL). This patch also fixes a potential
timeout leak (to_connect) in http_client_host_port (now http_client_queue)
and makes sure it is moved during switch_ioloop(). Finally it updates the
structure comment at the top of http-client.c.

diffstat:

 src/lib-http/Makefile.am           |    1 +
 src/lib-http/http-client-host.c    |  422 ++----------------------------------
 src/lib-http/http-client-peer.c    |   63 ++--
 src/lib-http/http-client-private.h |  354 ++++++++++++++++--------------
 src/lib-http/http-client-queue.c   |  375 ++++++++++++++++++++++++++++++++
 src/lib-http/http-client-request.c |    7 +-
 src/lib-http/http-client.c         |   57 +++-
 7 files changed, 668 insertions(+), 611 deletions(-)

diffs (truncated from 1540 to 300 lines):

diff -r cf38c8eb8493 -r 160e489d7c12 src/lib-http/Makefile.am
--- a/src/lib-http/Makefile.am	Fri Nov 22 22:05:52 2013 +0200
+++ b/src/lib-http/Makefile.am	Fri Nov 22 22:07:41 2013 +0200
@@ -21,6 +21,7 @@
 	http-client-request.c \
 	http-client-connection.c \
 	http-client-peer.c \
+	http-client-queue.c \
 	http-client-host.c \
 	http-client.c
 
diff -r cf38c8eb8493 -r 160e489d7c12 src/lib-http/http-client-host.c
--- a/src/lib-http/http-client-host.c	Fri Nov 22 22:05:52 2013 +0200
+++ b/src/lib-http/http-client-host.c	Fri Nov 22 22:07:41 2013 +0200
@@ -38,312 +38,19 @@
 }
 
 /*
- * Host:port
+ * Host
  */
 
 static void
-http_client_host_port_connection_setup(struct http_client_host_port *hport);
-
-static struct http_client_host_port *
-http_client_host_port_find(struct http_client_host *host,
-	const struct http_client_peer_addr *addr)
+http_client_host_lookup_failure(struct http_client_host *host,
+			      const char *error)
 {
-	struct http_client_host_port *hport;
-
-	array_foreach_modifiable(&host->ports, hport) {
-		if (hport->addr.type == addr->type && hport->addr.port == addr->port &&
-		    null_strcmp(hport->addr.https_name, addr->https_name) == 0)
-			return hport;
-	}
-
-	return NULL;
-}
-
-static struct http_client_host_port *
-http_client_host_port_init(struct http_client_host *host,
-	const struct http_client_peer_addr *addr)
-{
-	struct http_client_host_port *hport;
-
-	hport = http_client_host_port_find(host, addr);
-	if (hport == NULL) {
-		hport = array_append_space(&host->ports);
-		hport->host = host;
-		hport->addr = *addr;
-		hport->https_name = i_strdup(addr->https_name);
-		hport->addr.https_name = hport->https_name;
-		hport->ips_connect_idx = 0;
-		i_array_init(&hport->request_queue, 16);
-	}
-
-	return hport;
-}
-
-static void http_client_host_port_error(struct http_client_host_port *hport,
-	unsigned int status, const char *error)
-{
-	struct http_client_request **req;
-
-	/* abort all pending requests */
-	array_foreach_modifiable(&hport->request_queue, req) {
-		http_client_request_error(*req, status, error);
-	}
-	array_clear(&hport->request_queue);
-}
-
-static void http_client_host_port_deinit(struct http_client_host_port *hport)
-{
-	http_client_host_port_error
-		(hport, HTTP_CLIENT_REQUEST_ERROR_ABORTED, "Aborted");
-	i_free(hport->https_name);
-	if (array_is_created(&hport->pending_peers))
-		array_free(&hport->pending_peers);
-	array_free(&hport->request_queue);
-}
-
-static void
-http_client_host_port_drop_request(struct http_client_host_port *hport,
-	struct http_client_request *req)
-{
-	ARRAY_TYPE(http_client_request) *req_arr = &hport->request_queue;
-	struct http_client_request **req_idx;
-
-	array_foreach_modifiable(req_arr, req_idx) {
-		if (*req_idx == req) {
-			array_delete(req_arr, array_foreach_idx(req_arr, req_idx), 1);
-			break;
-		}
-	}
-}
-
-static bool
-http_client_hport_is_last_connect_ip(struct http_client_host_port *hport)
-{
-	i_assert(hport->ips_connect_idx < hport->host->ips_count);
-	i_assert(hport->ips_connect_start_idx < hport->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
-	   a ring buffer where we automatically wrap back to the first IP
-	   when necessary. */
-	return (hport->ips_connect_idx + 1) % hport->host->ips_count ==
-		hport->ips_connect_start_idx;
-}
-
-static void
-http_client_host_port_soft_connect_timeout(struct http_client_host_port *hport)
-{
-	struct http_client_host *host = hport->host;
-	const struct http_client_peer_addr *addr = &hport->addr;
-
-	if (hport->to_connect != NULL)
-		timeout_remove(&hport->to_connect);
-
-	if (http_client_hport_is_last_connect_ip(hport)) {
-		/* no more IPs to try */
-		return;
-	}
-
-	/* if our our previous connection attempt takes longer than the
-	   soft_connect_timeout, we start a connection attempt to the next IP in
-	   parallel */
-	http_client_host_debug(host, "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)); 
-
-	/* next IP */
-	hport->ips_connect_idx = (hport->ips_connect_idx + 1) % host->ips_count;
-
-	/* setup connection to new peer (can start new soft timeout) */
-	http_client_host_port_connection_setup(hport);
-}
-
-static void
-http_client_host_port_connection_setup(struct http_client_host_port *hport)
-{
-	struct http_client_host *host = hport->host;
-	struct http_client_peer *peer = NULL;
-	const struct http_client_peer_addr *addr = &hport->addr;
-	unsigned int num_requests = array_count(&hport->request_queue);
-
-	if (num_requests == 0)
-		return;
-
-	/* update our peer address */
-	hport->addr.ip = host->ips[hport->ips_connect_idx];
-
-	http_client_host_debug(host, "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);
-
-	/* create/get peer */
-	peer = http_client_peer_get(host->client, addr);
-	http_client_peer_add_host(peer, host);
-
-	/* handle requests; creates new connections when needed/possible */
-	http_client_peer_trigger_request_handler(peer);
-
-	if (!http_client_peer_is_connected(peer)) {
-		unsigned int msecs;
-
-		/* not already connected, wait for connections */
-		if (!array_is_created(&hport->pending_peers))
-			i_array_init(&hport->pending_peers, 8);
-		array_append(&hport->pending_peers, &peer, 1);			
-
-		/* start soft connect time-out (but only if we have another IP left) */
-		msecs = host->client->set.soft_connect_timeout_msecs;
-		if (!http_client_hport_is_last_connect_ip(hport) && msecs > 0 &&
-		    hport->to_connect == NULL) {
-			hport->to_connect =
-				timeout_add(msecs, http_client_host_port_soft_connect_timeout, hport);
-		}
-	}
-}
-
-static unsigned int
-http_client_host_get_ip_idx(struct http_client_host *host,
-			    const struct ip_addr *ip)
-{
-	unsigned int i;
-
-	for (i = 0; i < host->ips_count; i++) {
-		if (net_ip_compare(&host->ips[i], ip))
-			return i;
-	}
-	i_unreached();
-}
-
-static void
-http_client_host_port_connection_success(struct http_client_host_port *hport,
-					 const struct http_client_peer_addr *addr)
-{
-	/* we achieved at least one connection the the addr->ip */
-	hport->ips_connect_start_idx =
-		http_client_host_get_ip_idx(hport->host, &addr->ip);
-
-	/* stop soft connect time-out */
-	if (hport->to_connect != NULL)
-		timeout_remove(&hport->to_connect);
-
-	/* drop all other attempts to the hport. note that we get here whenever
-	   a connection is successfully created, so pending_peers array
-	   may be empty. */
-	if (array_is_created(&hport->pending_peers) &&
-		array_count(&hport->pending_peers) > 0) {
-		struct http_client_peer *const *peer_idx;
-
-		array_foreach(&hport->pending_peers, peer_idx) {
-			if (http_client_peer_addr_cmp(&(*peer_idx)->addr, addr) == 0) {
-				/* don't drop any connections to the successfully
-				   connected peer, even if some of the connections
-				   are pending. they may be intended for urgent
-				   requests. */
-				continue;
-			}
-			/* remove this host from the peer; if this was the last/only host, the
-			   peer will be freed, closing all connections.
-			 */
-			http_client_peer_remove_host(*peer_idx, hport->host);
-		}
-		array_clear(&hport->pending_peers);
-	}
-}
-
-static bool
-http_client_host_port_connection_failure(struct http_client_host_port *hport,
-	const struct http_client_peer_addr *addr, const char *reason)
-{
-	struct http_client_host *host = hport->host;
-
-	if (array_is_created(&hport->pending_peers) &&
-		array_count(&hport->pending_peers) > 0) {
-		struct http_client_peer *const *peer_idx;
-
-		/* we're still doing the initial connections to this hport. if
-		   we're also doing parallel connections with soft timeouts
-		   (pending_peer_count>1), wait for them to finish
-		   first. */
-		array_foreach(&hport->pending_peers, peer_idx) {
-			if (http_client_peer_addr_cmp(&(*peer_idx)->addr, addr) == 0) {
-				array_delete(&hport->pending_peers,
-					array_foreach_idx(&hport->pending_peers, peer_idx), 1);
-				break;
-			}
-		}
-		if (array_count(&hport->pending_peers) > 0)
-			return TRUE;
-	}
-
-	/* one of the connections failed. if we're not using soft timeouts,
-	   we need to try to connect to the next IP. if we are using soft
-	   timeouts, we've already tried all of the IPs by now. */
-	if (hport->to_connect != NULL)
-		timeout_remove(&hport->to_connect);
-
-	if (http_client_hport_is_last_connect_ip(hport)) {
-		/* all IPs failed, but retry all of them again on the
-		   next request. */
-		hport->ips_connect_idx = hport->ips_connect_start_idx =
-			(hport->ips_connect_idx + 1) % host->ips_count;
-		http_client_host_port_error(hport,
-			HTTP_CLIENT_REQUEST_ERROR_CONNECT_FAILED, reason);
-		return FALSE;
-	}
-	hport->ips_connect_idx = (hport->ips_connect_idx + 1) % host->ips_count;
-	http_client_host_port_connection_setup(hport);
-	return TRUE;
-}
-
-/*
- * Host
- */
-
-void http_client_host_connection_success(struct http_client_host *host,
-	const struct http_client_peer_addr *addr)
-{
-	struct http_client_host_port *hport;
-
-	http_client_host_debug(host, "Successfully connected to %s",
-		http_client_peer_addr2str(addr));
-
-	hport = http_client_host_port_find(host, addr);
-	if (hport == NULL)
-		return;
-
-	http_client_host_port_connection_success(hport, addr);
-}
-
-void http_client_host_connection_failure(struct http_client_host *host,


More information about the dovecot-cvs mailing list