changeset 17857:adcf35ac5432

lib-http: client: Fixed aborting request in the middle of sending payload. If the request payload is so big that it cannot be sent all at once, the caller may at some point abort the request when it is still being sent. The bug occurred when the request finally finished sending. It erroneously advanced the state to WAITING rather than remaining ABORTED, thus 'reviving' the request unexpectedly.
author Stephan Bosch <stephan@rename-it.nl>
date Wed, 01 Oct 2014 10:33:39 +0300
parents df53b5ccc2ba
children 548cb71d63da
files src/lib-http/http-client-connection.c src/lib-http/http-client-request.c
diffstat 2 files changed, 12 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-http/http-client-connection.c	Wed Oct 01 00:17:09 2014 +0300
+++ b/src/lib-http/http-client-connection.c	Wed Oct 01 10:33:39 2014 +0300
@@ -299,6 +299,7 @@
 	if (conn->peer->no_payload_sync)
 		req->payload_sync = FALSE;
 
+	i_assert(req->state == HTTP_REQUEST_STATE_QUEUED);
 	array_append(&conn->request_wait_list, &req, 1);
 	http_client_request_ref(req);
 
--- a/src/lib-http/http-client-request.c	Wed Oct 01 00:17:09 2014 +0300
+++ b/src/lib-http/http-client-request.c	Wed Oct 01 10:33:39 2014 +0300
@@ -453,14 +453,23 @@
 {
 	i_assert(req->conn != NULL);
 
+	/* drop payload output stream */
 	if (req->payload_output != NULL) {
 		o_stream_unref(&req->payload_output);
 		req->payload_output = NULL;
 	}
-	req->state = HTTP_REQUEST_STATE_WAITING;
+
+	/* advance state only when request didn't get aborted in the mean time */
+	if (req->state != HTTP_REQUEST_STATE_ABORTED) {
+		i_assert(req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT);
+		req->state = HTTP_REQUEST_STATE_WAITING;
+	}
+
+	/* release connection */
 	req->conn->output_locked = FALSE;
 
-	http_client_request_debug(req, "Finished sending payload");
+	http_client_request_debug(req, "Finished sending%s payload",
+		(req->state == HTTP_REQUEST_STATE_ABORTED ? " aborted" : ""));
 }
 
 static int