From: Stephan Bosch Date: Wed, 24 May 2017 19:59:32 +0000 (+0200) Subject: lib-http: client: When a request is destroyed prematurely during payload input, consi... X-Git-Tag: 2.3.0.rc1~1563 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7a1bc4683f3667f440df415b3f839e25046cc720;p=thirdparty%2Fdovecot%2Fcore.git 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. --- diff --git a/src/lib-http/http-client-connection.c b/src/lib-http/http-client-connection.c index f8f6391676..89ee354f80 100644 --- a/src/lib-http/http-client-connection.c +++ b/src/lib-http/http-client-connection.c @@ -646,7 +646,7 @@ static void http_client_payload_destroyed(struct http_client_request *req) 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 @@ void http_client_connection_request_destroyed( 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