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