changeset 22077:a75945a50239

imap: login reply should be sent sooner
author Josef 'Jeff' Sipek <jeff.sipek@dovecot.fi>
date Wed, 17 May 2017 11:40:53 +0300
parents 6b68ff970c9e
children f2b50a4a6951
files src/imap/main.c
diffstat 1 files changed, 53 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/src/imap/main.c	Tue Apr 04 00:32:07 2017 +0200
+++ b/src/imap/main.c	Wed May 17 11:40:53 2017 +0300
@@ -11,6 +11,7 @@
 #include "randgen.h"
 #include "restrict-access.h"
 #include "fd-close-on-exec.h"
+#include "write-full.h"
 #include "settings-parser.h"
 #include "master-interface.h"
 #include "master-service.h"
@@ -164,8 +165,8 @@
 }
 
 static void
-client_add_input(struct client *client, const unsigned char *client_input,
-		 size_t client_input_size)
+client_add_input_capability(struct client *client, const unsigned char *client_input,
+			    size_t client_input_size)
 {
 	struct ostream *output;
 	struct client_input input;
@@ -182,6 +183,7 @@
 		input.tag = getenv("IMAPLOGINTAG");
 	}
 
+	/* cork/uncork around the OK reply to minimize latency */
 	output = client->output;
 	o_stream_ref(output);
 	o_stream_cork(output);
@@ -202,6 +204,19 @@
 			input.tag, " OK [CAPABILITY ",
 			str_c(client->capability_string), "] Logged in", NULL));
 	}
+	o_stream_uncork(output);
+	o_stream_unref(&output);
+}
+
+static void
+client_add_input_finalize(struct client *client)
+{
+	struct ostream *output;
+
+	/* try to condense any responses into as few packets as possible */
+	output = client->output;
+	o_stream_ref(output);
+	o_stream_cork(output);
 	(void)client_handle_input(client);
 	o_stream_uncork(output);
 	o_stream_unref(&output);
@@ -214,6 +229,14 @@
 		client_continue_pending_input(client);
 }
 
+static void
+client_add_input(struct client *client, const unsigned char *client_input,
+		 size_t client_input_size)
+{
+	client_add_input_capability(client, client_input, client_input_size);
+	client_add_input_finalize(client);
+}
+
 int client_create_from_input(const struct mail_storage_service_input *input,
 			     int fd_in, int fd_out,
 			     struct client **client_r, const char **error_r)
@@ -268,6 +291,9 @@
 	if (client_create_from_input(&input, STDIN_FILENO, STDOUT_FILENO,
 				     &client, &error) < 0)
 		i_fatal("%s", error);
+
+	/* TODO: the following could make use of
+	   client_add_input_{capability,finalize} */
 	input_base64 = getenv("CLIENT_INPUT");
 	if (input_base64 == NULL)
 		client_add_input(client, NULL, 0);
@@ -313,8 +339,22 @@
 	flags = login_client->auth_req.flags;
 	if ((flags & MAIL_AUTH_REQUEST_FLAG_TLS_COMPRESSION) != 0)
 		client->tls_compression = TRUE;
-	client_add_input(client, login_client->data,
+	client_add_input_capability(client, login_client->data,
 			 login_client->auth_req.data_size);
+
+	/* finish initializing the user (see comment in main()) */
+	if (mail_namespaces_init(client->user, &error) < 0) {
+		if (write_full(login_client->fd, MSG_BYE_INTERNAL_ERROR,
+			       strlen(MSG_BYE_INTERNAL_ERROR)) < 0)
+			if (errno != EAGAIN && errno != EPIPE)
+				i_error("write_full(client) failed: %m");
+
+		i_error("%s", error);
+		client_destroy(client, error);
+		return;
+	}
+
+	client_add_input_finalize(client);
 	/* client may be destroyed now */
 }
 
@@ -376,7 +416,16 @@
 	} else {
 		service_flags |= MASTER_SERVICE_FLAG_KEEP_CONFIG_OPEN;
 		storage_service_flags |=
-			MAIL_STORAGE_SERVICE_FLAG_DISALLOW_ROOT;
+			MAIL_STORAGE_SERVICE_FLAG_DISALLOW_ROOT |
+			MAIL_STORAGE_SERVICE_FLAG_NO_NAMESPACES;
+
+		/*
+		 * We include MAIL_STORAGE_SERVICE_FLAG_NO_NAMESPACES so
+		 * that the mail_user initialization is fast and we can
+		 * quickly send back the OK response to LOGIN/AUTHENTICATE.
+		 * Otherwise we risk a very slow namespace initialization to
+		 * cause client timeouts on login.
+		 */
 	}
 
 	master_service = master_service_init("imap", service_flags,