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