dovecot-2.2: imap: URLFETCH error handling fixes.

dovecot at dovecot.org dovecot at dovecot.org
Tue Oct 23 20:16:21 EEST 2012


details:   http://hg.dovecot.org/dovecot-2.2/rev/3e70eacf67a4
changeset: 15235:3e70eacf67a4
user:      Timo Sirainen <tss at iki.fi>
date:      Tue Oct 23 20:07:06 2012 +0300
description:
imap: URLFETCH error handling fixes.

diffstat:

 src/imap/cmd-urlfetch.c                   |  60 ++++++++++++++++++------------
 src/lib-imap-urlauth/imap-urlauth-fetch.c |  17 ++++----
 src/lib-imap-urlauth/imap-urlauth-fetch.h |   3 +-
 3 files changed, 46 insertions(+), 34 deletions(-)

diffs (191 lines):

diff -r acd76b5272e9 -r 3e70eacf67a4 src/imap/cmd-urlfetch.c
--- a/src/imap/cmd-urlfetch.c	Tue Oct 23 12:59:41 2012 +0300
+++ b/src/imap/cmd-urlfetch.c	Tue Oct 23 20:07:06 2012 +0300
@@ -16,6 +16,7 @@
 struct cmd_urlfetch_context {
 	struct imap_urlauth_fetch *ufetch;
 	struct istream *input;
+	uoff_t size;
 
 	unsigned int failed:1;
 	unsigned int finished:1;
@@ -28,8 +29,7 @@
 	enum imap_urlauth_fetch_flags flags;
 };
 
-static void cmd_urlfetch_finish
-(struct client_command_context *cmd)
+static void cmd_urlfetch_finish(struct client_command_context *cmd)
 {
 	struct cmd_urlfetch_context *ctx =
 		(struct cmd_urlfetch_context *)cmd->context;
@@ -72,8 +72,6 @@
 	struct client *client = cmd->client;
 	struct cmd_urlfetch_context *ctx =
 		(struct cmd_urlfetch_context *)cmd->context;
-	const unsigned char *data;
-	size_t size;
 	int ret = 1;
 
 	/* are we in the middle of an urlfetch literal? */
@@ -88,25 +86,35 @@
 	}
 
 	/* transfer literal to client */
-	o_stream_set_max_buffer_size(client->output, 4096);
-	while (i_stream_read_data(ctx->input, &data, &size, 0) > 0) {
-		if ((ret = o_stream_send(client->output, data, size)) < 0)
-			break;
-		i_stream_skip(ctx->input, ret);
-	}
+	o_stream_set_max_buffer_size(client->output, 0);
+	ret = o_stream_send_istream(client->output, ctx->input);
 	o_stream_set_max_buffer_size(client->output, (size_t)-1);
 
-	if (ret < 0 || ctx->input->stream_errno != 0) {
-		/* fatal error */
+	if (ctx->input->v_offset == ctx->size) {
+		/* finished successfully */
+		i_stream_unref(&ctx->input);
+		return 1;
+	}
+	if (client->output->closed) {
+		/* client disconnected */
 		return -1;
 	}
+	if (ctx->input->stream_errno != 0) {
+		errno = ctx->input->stream_errno;
+		i_error("read(%s) failed: %m (URLFETCH)",
+			i_stream_get_name(ctx->input));
+		client_disconnect(client, "URLFETCH failed");
+		return -1;
+	}
+	if (!ctx->input->eof) {
+		o_stream_set_flush_pending(client->output, TRUE);
+		return 0;
+	}
 
-	if (!ctx->input->eof)
-		return 0;
-
-	/* finished */
-	i_stream_unref(&ctx->input);
-	return 1;
+	i_error("URLFETCH got too little data: %"PRIuUOFF_T" vs %"PRIuUOFF_T,
+		ctx->input->v_offset, ctx->size);
+	client_disconnect(client, "FETCH failed");
+	return -1;
 }
 
 static bool cmd_urlfetch_continue(struct client_command_context *cmd)
@@ -208,12 +216,12 @@
 
 	if (reply->input != NULL) {
 		ctx->input = reply->input;
+		ctx->size = reply->size;
 		i_stream_ref(reply->input);
 
 		ret = cmd_urlfetch_transfer_literal(cmd);
 		if (ret < 0) {
 			ctx->failed = TRUE;
-			cmd_urlfetch_finish(cmd);
 			return -1;
 		}
 		if (ret == 0) {
@@ -240,17 +248,20 @@
 	struct cmd_urlfetch_context *ctx = cmd->context;
 	int ret;
 
-	if (cmd->cancel)
-		return 1;
-
 	if (reply == NULL) {
 		/* fatal failure */
 		last = TRUE;
 		ctx->failed = TRUE;
 	} else if (reply->succeeded) {
 		/* URL fetch succeeded */
-		if ((ret = cmd_urlfetch_url_sucess(cmd, reply)) <= 0)
-			return ret;
+		ret = cmd_urlfetch_url_sucess(cmd, reply);
+		if (ret == 0)
+			return 0;
+		if (ret < 0) {
+			ctx->ufetch = NULL;
+			cmd_urlfetch_finish(cmd);
+			return -1;
+		}
 	} else {
 		/* URL fetch failed */
 		client_send_line(cmd->client,
@@ -262,6 +273,7 @@
 	}
 
 	if (last && cmd->state == CLIENT_COMMAND_STATE_WAIT_EXTERNAL) {
+		ctx->ufetch = NULL;
 		cmd_urlfetch_finish(cmd);
 		client_command_free(&cmd);
 	}
diff -r acd76b5272e9 -r 3e70eacf67a4 src/lib-imap-urlauth/imap-urlauth-fetch.c
--- a/src/lib-imap-urlauth/imap-urlauth-fetch.c	Tue Oct 23 12:59:41 2012 +0300
+++ b/src/lib-imap-urlauth/imap-urlauth-fetch.c	Tue Oct 23 20:07:06 2012 +0300
@@ -58,23 +58,20 @@
 	if (ufetch->local_url != NULL)
 		imap_msgpart_url_free(&ufetch->local_url);
 
-	if (ufetch->pending_reply.url != NULL)
-		i_free(ufetch->pending_reply.url);
+	i_free_and_null(ufetch->pending_reply.url);
+	i_free_and_null(ufetch->pending_reply.bodypartstruct);
+	i_free_and_null(ufetch->pending_reply.error);
 	if (ufetch->pending_reply.input != NULL)
 		i_stream_unref(&ufetch->pending_reply.input);
-	if (ufetch->pending_reply.bodypartstruct != NULL)
-		i_free(ufetch->pending_reply.bodypartstruct);
-	if (ufetch->pending_reply.error != NULL)
-		i_free(ufetch->pending_reply.error);
 
 	url = ufetch->local_urls_head;
-	while (url != NULL) {
+	for (; url != NULL; url = url_next) {
 		url_next = url->next;
 		i_free(url->url);
 		i_free(url);
 		ufetch->pending_requests--;
-		url = url_next;
 	}
+	ufetch->local_urls_head = ufetch->local_urls_tail = NULL;
 }
 
 static void imap_urlauth_fetch_abort(struct imap_urlauth_fetch *ufetch)
@@ -131,7 +128,7 @@
 	reply.flags = url_flags;
 	reply.succeeded = FALSE;
 	reply.error = error;
-	
+
 	T_BEGIN {
 		ret = ufetch->callback(&reply, ufetch->pending_requests == 0,
 				       ufetch->context);
@@ -298,6 +295,8 @@
 			imap_urlauth_fetch_abort_local(ufetch);
 		ufetch->failed = TRUE;
 	}
+	if (ret != 0)
+		imap_urlauth_fetch_deinit(&ufetch);
 	return ret;
 }
 
diff -r acd76b5272e9 -r 3e70eacf67a4 src/lib-imap-urlauth/imap-urlauth-fetch.h
--- a/src/lib-imap-urlauth/imap-urlauth-fetch.h	Tue Oct 23 12:59:41 2012 +0300
+++ b/src/lib-imap-urlauth/imap-urlauth-fetch.h	Tue Oct 23 20:07:06 2012 +0300
@@ -33,7 +33,8 @@
    for next reply, 0 if not all data was processed, and -1 for error. If a
    callback returns 0, imap_urlauth_connection_continue() must be called once
    new replies may be processed. If this is the last request to yield a reply,
-   argument last is TRUE */
+   argument last is TRUE. The callback must not call
+   imap_urlauth_fetch_deinit(). */
 typedef int
 imap_urlauth_fetch_callback_t(struct imap_urlauth_fetch_reply *reply,
 			      bool last, void *context);


More information about the dovecot-cvs mailing list