changeset 22213:f8d4ae988e7f

lib-http: client: When a request is destroyed prematurely during payload input, consider the payload stream destroyed and act accordingly. The application may hold a reference to the payload stream still, and it may be difficult to prevent that. This causes lib-http to keep waiting for the payload to be destroyed. When nothing else is going on, the current ioloop may then become empty, which caused the familiar assert failure.
author Stephan Bosch <stephan.bosch@dovecot.fi>
date Wed, 24 May 2017 21:59:32 +0200
parents 8cc50c161f4a
children 1b4a0735b158
files src/lib-http/http-client-connection.c
diffstat 1 files changed, 20 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-http/http-client-connection.c	Wed May 24 19:08:43 2017 +0200
+++ b/src/lib-http/http-client-connection.c	Wed May 24 21:59:32 2017 +0200
@@ -646,7 +646,7 @@
 void http_client_connection_request_destroyed(
 	struct http_client_connection *conn, struct http_client_request *req)
 {
-	struct istream *payload = conn->incoming_payload;
+	struct istream *payload;
 
 	i_assert(req->conn == conn);
 	if (conn->pending_request != req)
@@ -655,10 +655,28 @@
 	http_client_connection_debug(conn,
 		"Pending request destroyed prematurely");
 
-	if (payload == NULL)
+	payload = conn->incoming_payload;
+	if (payload == NULL) {
+		/* payload already gone */
 		return;
+	}
+
+	/* destroy the payload, so that the timeout istream is closed */
 	i_stream_ref(payload);
 	i_stream_destroy(&payload);
+
+	payload = conn->incoming_payload;
+	if (payload == NULL) {
+		/* not going to happen, but check for it anyway */
+		return;
+	}
+
+	/* the application still holds a reference to the payload stream, but it
+	   is closed and we don't care about it anymore, so act as though it is
+	   destroyed. */
+	i_stream_remove_destroy_callback(payload,
+					 http_client_payload_destroyed);
+	http_client_payload_destroyed(req);
 }
 
 static bool