dovecot-2.2: lib-http: Fixed detecting disconnection when ioloop...

dovecot at dovecot.org dovecot at dovecot.org
Sat Oct 4 14:33:37 UTC 2014


details:   http://hg.dovecot.org/dovecot-2.2/rev/77c4b78a4fa2
changeset: 17882:77c4b78a4fa2
user:      Stephan Bosch <stephan at rename-it.nl>
date:      Sat Oct 04 17:32:48 2014 +0300
description:
lib-http: Fixed detecting disconnection when ioloop is running only intermittently.
This fix only applies to ioloops created and run by lib-http itself.

diffstat:

 src/lib-http/http-client-connection.c |  60 +++++++++++++++++++++++++---------
 src/lib-http/http-client-private.h    |   1 +
 src/lib-http/http-client-request.c    |  30 ++++++++++-------
 3 files changed, 62 insertions(+), 29 deletions(-)

diffs (138 lines):

diff -r 4f175c27bea5 -r 77c4b78a4fa2 src/lib-http/http-client-connection.c
--- a/src/lib-http/http-client-connection.c	Sat Oct 04 17:32:48 2014 +0300
+++ b/src/lib-http/http-client-connection.c	Sat Oct 04 17:32:48 2014 +0300
@@ -58,23 +58,6 @@
 	return pending_count;
 }
 
-bool http_client_connection_is_ready(struct http_client_connection *conn)
-{
-	if (conn->in_req_callback) {
-		/* this can happen when a nested ioloop is created inside request
-		   callback. we currently don't reuse connections that are occupied
-		   this way, but theoretically we could, although that would add
-		   quite a bit of complexity.
-		 */
-		return FALSE;
-	}
-
-	return (conn->connected && !conn->output_locked &&
-		!conn->close_indicated && !conn->tunneling &&
-		http_client_connection_count_pending(conn) <
-			conn->client->set.max_pipelined_requests);
-}
-
 bool http_client_connection_is_idle(struct http_client_connection *conn)
 {
 	return (conn->to_idle != NULL);
@@ -174,6 +157,48 @@
 	http_client_connection_unref(_conn);
 }
 
+bool http_client_connection_is_ready(struct http_client_connection *conn)
+{
+	int ret;
+
+	if (conn->in_req_callback) {
+		/* this can happen when a nested ioloop is created inside request
+		   callback. we currently don't reuse connections that are occupied
+		   this way, but theoretically we could, although that would add
+		   quite a bit of complexity.
+		 */
+		return FALSE;
+	}
+
+	if (!conn->connected || conn->output_locked ||
+		conn->close_indicated || conn->tunneling ||
+		http_client_connection_count_pending(conn) >=
+			conn->client->set.max_pipelined_requests)
+		return FALSE;
+
+	if (conn->last_ioloop != NULL && conn->last_ioloop != current_ioloop) {
+		conn->last_ioloop = current_ioloop;
+		/* Active ioloop is different from what we saw earlier;
+		   we may have missed a disconnection event on this connection.
+		   Verify status by reading from connection. */
+		if ((ret=i_stream_read(conn->conn.input)) < 0) {
+			int stream_errno = conn->conn.input->stream_errno;
+
+			i_assert(ret != -2);
+			i_assert(conn->conn.input->stream_errno != 0 || conn->conn.input->eof);
+			http_client_connection_abort_temp_error(&conn,
+				HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST,
+				t_strdup_printf("Connection lost: read(%s) failed: %s",
+						i_stream_get_name(conn->conn.input),
+						stream_errno != 0 ?
+						i_stream_get_error(conn->conn.input) :
+						"EOF"));
+			return FALSE;
+		}
+	}
+	return TRUE;
+}
+
 static void
 http_client_connection_idle_timeout(struct http_client_connection *conn)
 {
@@ -802,6 +827,7 @@
 {
 	/* connected */
 	conn->connected = TRUE;
+	conn->last_ioloop = current_ioloop;
 	if (conn->to_connect != NULL &&
 	    (conn->ssl_iostream == NULL ||
 	     ssl_iostream_is_handshaked(conn->ssl_iostream)))
diff -r 4f175c27bea5 -r 77c4b78a4fa2 src/lib-http/http-client-private.h
--- a/src/lib-http/http-client-private.h	Sat Oct 04 17:32:48 2014 +0300
+++ b/src/lib-http/http-client-private.h	Sat Oct 04 17:32:48 2014 +0300
@@ -131,6 +131,7 @@
 	struct http_client_request *pending_request;
 	struct istream *incoming_payload;
 	struct io *io_req_payload;
+	struct ioloop *last_ioloop;
 
 	/* requests that have been sent, waiting for response */
 	ARRAY_TYPE(http_client_request) request_wait_list;
diff -r 4f175c27bea5 -r 77c4b78a4fa2 src/lib-http/http-client-request.c
--- a/src/lib-http/http-client-request.c	Sat Oct 04 17:32:48 2014 +0300
+++ b/src/lib-http/http-client-request.c	Sat Oct 04 17:32:48 2014 +0300
@@ -792,21 +792,27 @@
 					   o_stream_get_name(output),
 					   o_stream_get_error(output));
 		ret = -1;
-	}
+	} else {
+		http_client_request_debug(req, "Sent header");
 
-	http_client_request_debug(req, "Sent header");
-
-	if (ret >= 0 && req->payload_output != NULL) {
-		if (!req->payload_sync) {
-			if (http_client_request_send_more(req, error_r) < 0)
-				ret = -1;
+		if (req->payload_output != NULL) {
+			if (!req->payload_sync) {
+				if (http_client_request_send_more(req, error_r) < 0)
+					ret = -1;
+			} else {
+				http_client_request_debug(req, "Waiting for 100-continue");
+				conn->output_locked = TRUE;
+			}
 		} else {
-			http_client_request_debug(req, "Waiting for 100-continue");
-			conn->output_locked = TRUE;
+			req->state = HTTP_REQUEST_STATE_WAITING;
+			conn->output_locked = FALSE;
 		}
-	} else {
-		req->state = HTTP_REQUEST_STATE_WAITING;
-		conn->output_locked = FALSE;
+		if (ret >= 0 && o_stream_flush(output) < 0) {
+			*error_r = t_strdup_printf("flush(%s) failed: %s",
+   	                   o_stream_get_name(output),
+           	           o_stream_get_error(output));
+			ret = -1;
+		}
 	}
 	o_stream_uncork(output);
 	return ret;


More information about the dovecot-cvs mailing list