dovecot-2.2: imap: Various fixes to APPEND error handling.

dovecot at dovecot.org dovecot at dovecot.org
Wed Aug 29 18:35:13 EEST 2012


details:   http://hg.dovecot.org/dovecot-2.2/rev/20ad509a559a
changeset: 14972:20ad509a559a
user:      Timo Sirainen <tss at iki.fi>
date:      Wed Aug 29 18:32:13 2012 +0300
description:
imap: Various fixes to APPEND error handling.

diffstat:

 src/imap/cmd-append.c |  240 +++++++++++++++++++++++--------------------------
 1 files changed, 112 insertions(+), 128 deletions(-)

diffs (truncated from 521 to 300 lines):

diff -r 075dcb7eac58 -r 20ad509a559a src/imap/cmd-append.c
--- a/src/imap/cmd-append.c	Wed Aug 29 18:32:01 2012 +0300
+++ b/src/imap/cmd-append.c	Wed Aug 29 18:32:13 2012 +0300
@@ -50,7 +50,7 @@
 
 static void cmd_append_finish(struct cmd_append_context *ctx);
 static bool cmd_append_continue_message(struct client_command_context *cmd);
-static bool cmd_append_continue_parsing(struct client_command_context *cmd);
+static bool cmd_append_parse_new_msg(struct client_command_context *cmd);
 
 static const char *get_disconnect_reason(struct cmd_append_context *ctx)
 {
@@ -147,56 +147,6 @@
 		mailbox_free(&ctx->box);
 }
 
-static bool cmd_append_continue_cancel(struct client_command_context *cmd)
-{
-	struct cmd_append_context *ctx = cmd->context;
-
-	if (cmd->cancel) {
-		cmd_append_finish(ctx);
-		return TRUE;
-	}
-
-	(void)i_stream_read(ctx->litinput);
-	i_stream_skip(ctx->litinput, i_stream_get_data_size(ctx->litinput));
-
-	if (cmd->client->input->closed) {
-		cmd_append_finish(ctx);
-		return TRUE;
-	}
-
-	if (ctx->litinput->v_offset == ctx->literal_size) {
-		/* finished, but with MULTIAPPEND and LITERAL+ we may get
-		   more messages. */
-		i_stream_unref(&ctx->litinput);
-
-		ctx->message_input = FALSE;
-		imap_parser_reset(ctx->save_parser);
-		cmd->func = cmd_append_continue_parsing;
-		return cmd_append_continue_parsing(cmd);
-	}
-
-	return FALSE;
-}
-
-static bool cmd_append_cancel(struct cmd_append_context *ctx, bool nonsync)
-{
-	ctx->failed = TRUE;
-
-	if (!nonsync) {
-		cmd_append_finish(ctx);
-		return TRUE;
-	}
-
-	/* we have to read the nonsynced literal so we don't treat the message
-	   data as commands. */
-	ctx->litinput = i_stream_create_limit(ctx->client->input, ctx->literal_size);
-
-	ctx->message_input = TRUE;
-	ctx->cmd->func = cmd_append_continue_cancel;
-	ctx->cmd->context = ctx;
-	return cmd_append_continue_cancel(ctx->cmd);
-}
-
 static int
 cmd_append_catenate_url(struct client_command_context *cmd, const char *caturl)
 {
@@ -207,6 +157,9 @@
 	const char *error;
 	int ret;
 
+	if (ctx->failed)
+		return -1;
+
 	ret = imap_msgpart_url_parse(cmd->client->user, cmd->client->mailbox,
 				     caturl, &mpurl, &error);
 	if (ret < 0) {
@@ -275,24 +228,22 @@
 	return ret;
 }
 
-static int cmd_append_catenate_text(struct client_command_context *cmd)
+static void cmd_append_catenate_text(struct client_command_context *cmd)
 {
 	struct cmd_append_context *ctx = cmd->context;
-	uoff_t newsize;
 
-	newsize = ctx->cat_msg_size + ctx->literal_size;
-	if (newsize < ctx->cat_msg_size) {
+	if (ctx->literal_size > (uoff_t)-1 - ctx->cat_msg_size &&
+	    !ctx->failed) {
 		client_send_tagline(cmd,
 			"NO [TOOBIG] Composed message grows too big.");
-		return -1;
+		ctx->failed = TRUE;
 	}
 
 	/* save the mail */
-	ctx->cat_msg_size = newsize;
+	ctx->cat_msg_size += ctx->literal_size;
 	ctx->litinput = i_stream_create_limit(cmd->client->input,
 					      ctx->literal_size);
 	i_stream_chain_append(ctx->catchain, ctx->litinput);
-	return 0;
 }
 
 static int
@@ -304,9 +255,6 @@
 
 	*nonsync_r = FALSE;
 
-	if (ctx->failed)
-		return -1;
-
 	/* Handle URLs until a TEXT literal is encountered */
 	while (imap_arg_get_atom(args, &catpart)) {
 		const char *caturl;
@@ -316,21 +264,26 @@
 			args++;
 			if (!imap_arg_get_astring(args, &caturl))
 				break;
-			if (cmd_append_catenate_url(cmd, caturl) < 0)
-				return -1;
+			if (cmd_append_catenate_url(cmd, caturl) < 0) {
+				/* delay failure until we can stop
+				   parsing input */
+				ctx->failed = TRUE;
+			}
 		} else if (strcasecmp(catpart, "TEXT") == 0) {
 			/* TEXT <literal> */
 			args++;
 			if (!imap_arg_get_literal_size(args, &ctx->literal_size))
 				break;
-			if (args->literal8 && !ctx->binary_input) {
+			if (args->literal8 && !ctx->binary_input &&
+			    !ctx->failed) {
 				client_send_tagline(cmd,
 					"NO ["IMAP_RESP_CODE_UNKNOWN_CTE"] "
 					"Binary input allowed only when the first part is binary.");
-				return -1;
+				ctx->failed = TRUE;
 			}
 			*nonsync_r = args->type == IMAP_ARG_LITERAL_SIZE_NONSYNC;
-			return cmd_append_catenate_text(cmd) < 0 ? -1 : 1;
+			cmd_append_catenate_text(cmd);
+			return 1;
 		} else {
 			break;
 		}
@@ -342,6 +295,7 @@
 		return 0;
 	}
 	client_send_command_error(cmd, "Invalid arguments.");
+	cmd->client->input_skip_line = TRUE;
 	return -1;
 }
 
@@ -352,15 +306,19 @@
 	i_stream_chain_append_eof(ctx->catchain);
 	i_stream_unref(&ctx->input);
 	ctx->catenate = FALSE;
+	ctx->catchain = NULL;
 
-	/* do mailbox_save_continue() once more after appending EOF,
-	   to finish any pending reads */
-	if (mailbox_save_continue(ctx->save_ctx) < 0) {
-		mailbox_save_cancel(&ctx->save_ctx);
-		ctx->failed = TRUE;
-	} else if (mailbox_save_finish(&ctx->save_ctx) < 0) {
-		ctx->failed = TRUE;
-		client_send_storage_error(cmd, ctx->storage);
+	if (ctx->save_ctx == NULL) {
+		/* APPEND has already failed */
+		i_assert(ctx->failed);
+	} else {
+		/* do mailbox_save_continue() once more after appending EOF,
+		   to finish any pending reads */
+		(void)mailbox_save_continue(ctx->save_ctx);
+		if (mailbox_save_finish(&ctx->save_ctx) < 0) {
+			client_send_storage_error(cmd, ctx->storage);
+			ctx->failed = TRUE;
+		}
 	}
 }
 
@@ -374,22 +332,22 @@
 	int ret;
 
 	if (cmd->cancel) {
+		/* cancel the command immediately (disconnection) */
 		cmd_append_finish(ctx);
 		return TRUE;
 	}
 
+	/* we're parsing inside CATENATE (..) list after handling a TEXT part */
 	ret = imap_parser_read_args(ctx->save_parser, 0,
 				    IMAP_PARSE_FLAG_LITERAL_SIZE |
 				    IMAP_PARSE_FLAG_LITERAL8 |
 				    IMAP_PARSE_FLAG_INSIDE_LIST, &args);
 	if (ret == -1) {
-		if (!ctx->failed) {
-			msg = imap_parser_get_error(ctx->save_parser, &fatal);
-			if (fatal)
-				client_disconnect_with_error(client, msg);
-			else
-				client_send_command_error(cmd, msg);
-		}
+		msg = imap_parser_get_error(ctx->save_parser, &fatal);
+		if (fatal)
+			client_disconnect_with_error(client, msg);
+		else if (!ctx->failed)
+			client_send_command_error(cmd, msg);
 		client->input_skip_line = TRUE;
 		cmd_append_finish(ctx);
 		return TRUE;
@@ -400,8 +358,9 @@
 	}
 
 	if ((ret = cmd_append_catenate(cmd, args, &nonsync)) < 0) {
-		client->input_skip_line = TRUE;
-		return cmd_append_cancel(ctx, nonsync);
+		/* invalid parameters, abort immediately */
+		cmd_append_finish(ctx);
+		return TRUE;
 	}
 
 	if (ret == 0) {
@@ -410,8 +369,8 @@
 
 		/* last catenate part */
 		imap_parser_reset(ctx->save_parser);
-		cmd->func = cmd_append_continue_parsing;
-		return cmd_append_continue_parsing(cmd);
+		cmd->func = cmd_append_parse_new_msg;
+		return cmd_append_parse_new_msg(cmd);
 	}
 
 	/* TEXT <literal> */
@@ -420,12 +379,18 @@
 	client->input_skip_line = TRUE;
 
 	if (!nonsync) {
+		if (ctx->failed) {
+			/* tagline was already sent, we can abort here */
+			cmd_append_finish(ctx);
+			return TRUE;
+		}
 		o_stream_nsend(client->output, "+ OK\r\n", 6);
 		o_stream_nflush(client->output);
 		o_stream_uncork(client->output);
 		o_stream_cork(client->output);
 	}
 
+	i_assert(ctx->litinput != NULL);
 	ctx->message_input = TRUE;
 	cmd->func = cmd_append_continue_message;
 	return cmd_append_continue_message(cmd);
@@ -462,6 +427,7 @@
 		(*args)++;
 	}
 
+	/* <message literal> | CATENATE (..) */
 	valid = FALSE;
 	*nonsync_r = FALSE;
 	ctx->catenate = FALSE;
@@ -485,17 +451,15 @@
 
 	if (!valid) {
 		client->input_skip_line = TRUE;
-		client_send_command_error(cmd, "Invalid arguments.");
+		if (!ctx->failed)
+			client_send_command_error(cmd, "Invalid arguments.");
 		return -1;
 	}
 
-	if (ctx->failed) {
-		/* we failed earlier, make sure we just eat nonsync-literal
-		   if it's given. */
-		return -1;
-	}
-
-	if (flags_list != NULL) {
+	if (flags_list == NULL || ctx->failed) {
+		flags = 0;
+		keywords = NULL;
+	} else {
 		if (!client_parse_mail_flags(cmd, flags_list,
 					     &flags, &keywords_list))
 			return -1;
@@ -503,21 +467,19 @@
 			keywords = NULL;
 		else if (mailbox_keywords_create(ctx->box, keywords_list,
 						 &keywords) < 0) {
+			/* invalid keywords - delay failure */
 			client_send_storage_error(cmd, ctx->storage);
-			return -1;
+			ctx->failed = TRUE;
 		}


More information about the dovecot-cvs mailing list