dovecot-2.2: lib-http: If http_client_request_submit() fails, do...

dovecot at dovecot.org dovecot at dovecot.org
Thu Apr 4 14:11:16 EEST 2013


details:   http://hg.dovecot.org/dovecot-2.2/rev/b4927eea33fd
changeset: 16147:b4927eea33fd
user:      Timo Sirainen <tss at iki.fi>
date:      Thu Apr 04 14:11:10 2013 +0300
description:
lib-http: If http_client_request_submit() fails, don't immediately call the callback.
This simplifies the caller's error handling since there is now only one
error code path instead of two.

diffstat:

 src/lib-http/http-client-host.c    |  11 +++++++++
 src/lib-http/http-client-private.h |   8 ++++++
 src/lib-http/http-client-request.c |  44 ++++++++++++++++++++++++++++++++++++-
 3 files changed, 61 insertions(+), 2 deletions(-)

diffs (145 lines):

diff -r ace3911ca077 -r b4927eea33fd src/lib-http/http-client-host.c
--- a/src/lib-http/http-client-host.c	Thu Apr 04 13:21:42 2013 +0300
+++ b/src/lib-http/http-client-host.c	Thu Apr 04 14:11:10 2013 +0300
@@ -278,6 +278,7 @@
 		host->client = client;
 		host->name = i_strdup(hostname);
 		i_array_init(&host->ports, 4);
+		i_array_init(&host->delayed_failing_requests, 1);
 
 		hostname = host->name;
 		hash_table_insert(client->hosts, hostname, host);
@@ -397,6 +398,9 @@
 	}
 	array_free(&host->ports);
 
+	i_assert(array_count(&host->delayed_failing_requests) == 0);
+	array_free(&host->delayed_failing_requests);
+
 	i_free(host->ips);
 	i_free(host->name);
 	i_free(host);
@@ -404,6 +408,13 @@
 
 void http_client_host_switch_ioloop(struct http_client_host *host)
 {
+	struct http_client_request **req;
+
 	if (host->dns_lookup != NULL)
 		dns_lookup_switch_ioloop(host->dns_lookup);
+	array_foreach_modifiable(&host->delayed_failing_requests, req) {
+		(*req)->to_delayed_error =
+			io_loop_move_timeout(&(*req)->to_delayed_error);
+	}
+
 }
diff -r ace3911ca077 -r b4927eea33fd src/lib-http/http-client-private.h
--- a/src/lib-http/http-client-private.h	Thu Apr 04 13:21:42 2013 +0300
+++ b/src/lib-http/http-client-private.h	Thu Apr 04 14:11:10 2013 +0300
@@ -50,6 +50,10 @@
 	unsigned int attempts;
 	unsigned int redirects;
 
+	unsigned int delayed_error_status;
+	const char *delayed_error;
+	struct timeout *to_delayed_error;
+
 	http_client_request_callback_t *callback;
 	void *context;
 
@@ -63,6 +67,7 @@
 	unsigned int payload_wait:1;
 	unsigned int ssl:1;
 	unsigned int urgent:1;
+	unsigned int submitted:1;
 };
 
 struct http_client_host_port {
@@ -87,6 +92,9 @@
 	unsigned int ips_count;
 	struct ip_addr *ips;
 
+	/* list of requests in this host that are waiting for ioloop */
+	ARRAY(struct http_client_request *) delayed_failing_requests;
+
 	/* requests are managed on a per-port basis */
 	ARRAY_TYPE(http_client_host_port) ports;
 
diff -r ace3911ca077 -r b4927eea33fd src/lib-http/http-client-request.c
--- a/src/lib-http/http-client-request.c	Thu Apr 04 13:21:42 2013 +0300
+++ b/src/lib-http/http-client-request.c	Thu Apr 04 14:11:10 2013 +0300
@@ -81,6 +81,23 @@
 	req->refcount++;
 }
 
+static void http_client_request_remove_delayed(struct http_client_request *req)
+{
+	struct http_client_request *const *reqs;
+	unsigned int i, count;
+
+	timeout_remove(&req->to_delayed_error);
+
+	reqs = array_get(&req->host->delayed_failing_requests, &count);
+	for (i = 0; i < count; i++) {
+		if (reqs[i] == req) {
+			array_delete(&req->host->delayed_failing_requests, i, 1);
+			return;
+		}
+	}
+	i_unreached();
+}
+
 void http_client_request_unref(struct http_client_request **_req)
 {
 	struct http_client_request *req = *_req;
@@ -101,6 +118,8 @@
 	if (client->pending_requests == 0 && client->ioloop != NULL)
 		io_loop_stop(client->ioloop);
 
+	if (req->to_delayed_error != NULL)
+		http_client_request_remove_delayed(req);
 	if (req->payload_input != NULL)
 		i_stream_unref(&req->payload_input);
 	if (req->payload_output != NULL)
@@ -193,6 +212,7 @@
 	req->client->pending_requests++;
 
 	http_client_request_do_submit(req);
+	req->submitted = TRUE;
 }
 
 static void
@@ -454,11 +474,31 @@
 	}
 }
 
+static void http_client_request_error_delayed(struct http_client_request *req)
+{
+	http_client_request_remove_delayed(req);
+	http_client_request_send_error(req, req->delayed_error_status,
+				       req->delayed_error);
+	http_client_request_unref(&req);
+}
+
 void http_client_request_error(struct http_client_request *req,
 	unsigned int status, const char *error)
 {
-	http_client_request_send_error(req, status, error);
-	http_client_request_unref(&req);
+	if (!req->submitted) {
+		/* we're still in http_client_request_submit(). delay
+		   reporting the error, so the caller doesn't have to handle
+		   immediate callbacks. */
+		i_assert(req->delayed_error == NULL);
+		req->delayed_error = p_strdup(req->pool, error);
+		req->delayed_error_status = status;
+		req->to_delayed_error = timeout_add_short(0,
+			http_client_request_error_delayed, req);
+		array_append(&req->host->delayed_failing_requests, &req, 1);
+	} else {
+		http_client_request_send_error(req, status, error);
+		http_client_request_unref(&req);
+	}
 }
 
 void http_client_request_abort(struct http_client_request **_req)


More information about the dovecot-cvs mailing list